内容类型为application / x-www-form-urlencoded的HTTP Post请求在Spring Boot服务中不起作用

时间:2018-12-02 18:36:44

标签: java android spring spring-boot retrofit2

我最近刚开始使用Spring Boot,我正在尝试通过Retrofit2 Rest API库从一个Android应用程序发出HTTP POST请求,并使用application / x-www-form-url编码,但是当我点击spring boot POST服务时,它向我显示错误以下

  

“状态”:415,“错误”:“不受支持的媒体   类型“,”异常“:” org.springframework.web.HttpMediaTypeNotSupportedException“,”消息“:”内容   类型'application / x-www-form-urlencoded; charset = UTF-8'不是   支持”,“路径”:“ / api / login”

enter image description here

有人知道如何解决吗?

这是我的代码Android代码示例

ApiService.java

public interface ApiService {
    @FormUrlEncoded
    @POST("/api/login")
    Call<LoginData> postLogIn(
            @Field("username") String username,
            @Field("password") String password);
}

ApiHandler.java

    private static final String SERVER_URL = "http://192.168.0.12:8080/";
    private static final long CONNECTION_TIMEOUT = 30;
    public static Retrofit restAdapter;

    //public static final int CONNECTION_TIME_OUT = 120;
    private static Retrofit getRestAdapter() {
        if (restAdapter == null) {
            restAdapter = new Retrofit.Builder()
                    .baseUrl(SERVER_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .client(getClient()).build();
        }
        return restAdapter;
    }

    private static OkHttpClient getClient() {
        OkHttpClient.Builder okClientBuilder = new OkHttpClient.Builder();
        HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
        httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        okClientBuilder.addInterceptor(httpLoggingInterceptor);
        okClientBuilder.connectTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS);
        okClientBuilder.readTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS);
        okClientBuilder.writeTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS);
        return okClientBuilder.build();
    }

PostHandler.java

@Override
    public void callAPI(final Context context, final ApiClientResponse callback, Object arg0) {
        this.callback = callback;
        apiService.postLogIn(Login.username, Login.password).enqueue(new Callback<LoginData>() {
            @Override
            public void onResponse(Call<LoginData> call, Response<LoginData> response) {
                if (response.isSuccessful()) {
                    LoginData loginData = response.body();
                    successLoginData = loginData;
                    successCallBack();
                } else {
                    ApiErrorHandler.handleError(context, response, errorResponse);
                }
            }

            @Override
            public void onFailure(Call<LoginData> call, Throwable t) {
                ApiErrorHandler.handleError(context, t, errorResponse);
            }

            RetrofitErrorResponse errorResponse = new RetrofitErrorResponse() {
                @Override
                public void errorMessage(String errorMessage) {
                    failureCallBack(errorMessage);
                }

                @Override
                public void tSyncError() {

                }

                @Override
                public void invalidTokenError() {

                }
            };

        });
    }

LoginData.java模型类

@Generated("org.jsonschema2pojo")
public class LoginData {
    @SerializedName("access_token")
    @Expose
    private String accessToken;
    @SerializedName("token_type")
    @Expose
    private String tokenType;
    @SerializedName("refresh_token")
    @Expose
    private String refreshToken;
    @SerializedName("expires_in")
    @Expose
    private long expiresIn;
    @SerializedName("scope")
    @Expose
    private String scope;

    // getter setter 
}

这是我的Spring引导应用程序代码示例

MainApplicationClass.java

@SpringBootApplication
public class MainApplicationClass {
    public static void main(String[] args) {
        SpringApplication.run(MainApplicationClass.class, args);
    }
}

Controller.java

@RestController
public class BlogController {
    @Autowired
    BlogRespository blogRespository;
    BlogMockedData blogMockedData = BlogMockedData.getInstance();

    @GetMapping("/blog")
    public List<Blog> index() {
        return blogMockedData.fetchBlogList();
    }

    @GetMapping("/blog/{id}")
    public Blog show(@PathVariable String id) {
        int blogId = Integer.parseInt(id);
        return blogMockedData.getBlogById(blogId);
    }

    @PostMapping(value = "/api/login",
            consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_FORM_URLENCODED_VALUE},
            produces = {MediaType.APPLICATION_JSON_UTF8_VALUE, MediaType.APPLICATION_JSON_VALUE}
    )
    public LoginData postLogin(@RequestBody Map<String, String> body) {
        String userName = body.get("username");
        String password = body.get("password");
        return blogMockedData.getLoginToken(userName, password);
    }

注意::如果我从POSTMAN中启动了spring boot POST服务,我将得到低于结果

enter image descriptiIn here

但是,如果我从Android客户端访问POST服务,则会收到错误消息

  

“状态”:415,“错误”:“不受支持的媒体   类型“,”异常“:” org.springframework.web.HttpMediaTypeNotSupportedException“,”消息“:”内容   类型'application / x-www-form-urlencoded; charset = UTF-8'不是   支持”,“路径”:“ / api / login”

3 个答案:

答案 0 :(得分:0)

要使Spring正确加载表单编码数据,您需要将端点参数定义为:

public LoginData postLogin(@RequestBody MultiValueMap<String, String> body)

public LoginData postLogin(@RequestParam Map<String, String> body)

答案 1 :(得分:0)

使用application / x-www-form-urlencoded时,Spring不能将其理解为RequestBody。因此,在映射数据的参数列表中删除@RequestBody批注,因为我在那里可以看到它。

请阅读此Spring doesn't understand application/x-www-form-urlencoded

答案 2 :(得分:0)

在 Spring Boot 中处理 URL 编码的 POST ( Content-Type: application/x-www-form-urlencoded )

这不起作用:

    public String processForm(@RequestBody RespFormDTO formDTO, 
HttpServletRequest request, HttpServletResponse response) {

这会起作用:

public String processForm(RespFormDTO formDTO,
       HttpServletRequest request, HttpServletResponse response) {