内容类型为 application/x-www-form-urlencoded 的 HTTP Post 请求在 Spring 引导服务中不起作用
Posted
技术标签:
【中文标题】内容类型为 application/x-www-form-urlencoded 的 HTTP Post 请求在 Spring 引导服务中不起作用【英文标题】:HTTP Post request with content type application/x-www-form-urlencoded not working in Spring boot service 【发布时间】:2019-05-04 03:13:10 【问题描述】:我最近刚接触 Spring Boot,我正在尝试通过 Retrofit2 REST API 库从一个 android 应用程序发出 HTTP POST 请求,并使用 application/x-www-form-url 编码,但是当我点击我的 Spring Boot POST 服务时,它显示了我以下错误
"status":415,"error":"不支持的媒体 类型","异常":"org.springframework.web.HttpMediaTypeNotSupportedException","消息":"内容 输入 'application/x-www-form-urlencoded;charset=UTF-8' 不是 支持","路径":"/api/login"
有人知道怎么解决吗?
这是我的代码 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 Boot 应用程序代码示例
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 服务,我会得到以下结果
但是,如果我从我的 android 客户端点击 POST 服务,它会给我带来错误
"status":415,"error":"不支持的媒体 类型","异常":"org.springframework.web.HttpMediaTypeNotSupportedException","消息":"内容 输入 'application/x-www-form-urlencoded;charset=UTF-8' 不是 支持","路径":"/api/login"
【问题讨论】:
【参考方案1】:为了让 Spring 正确加载表单编码数据,您需要将端点参数定义为:
public LoginData postLogin(@RequestBody MultiValueMap<String, String> body)
或
public LoginData postLogin(@RequestParam Map<String, String> body)
【讨论】:
嗨@bluurr 我应用了你的答案,但仍然得到同样的错误 您好,您使用的是哪个版本的 Spring boot? hi @bluurr使用 application/x-www-form-urlencoded 时,Spring 不会将其理解为 RequestBody。因此,请删除映射数据的参数列表中的 @RequestBody 注释,因为我可以在那里看到它。
请阅读此Spring doesn't understand application/x-www-form-urlencoded
【讨论】:
嗨 @dexter 已经应用了这个解决方案,但仍然出现同样的错误【参考方案3】:在 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)
【讨论】:
【参考方案4】:当标头 Content-Type:application/x-www-form-urlencoded 添加到我对 Springboot 应用程序的请求时,我遇到了类似的问题。请求正文为空。
我按照链接下方的说明进行操作,并且成功了。
简答,你需要禁用 HiddenHttpMethodFilter
下面的链接解释了原因以及如何禁用
https://newbedev.com/why-is-httpservletrequest-inputstream-empty
【讨论】:
以上是关于内容类型为 application/x-www-form-urlencoded 的 HTTP Post 请求在 Spring 引导服务中不起作用的主要内容,如果未能解决你的问题,请参考以下文章
cocos2d-js网络教程篇cocos2d-js http网络请求