ajax调用后台controller方法时报415 (Unsupported Media Type)错误
spring mvc 下,ajax调用后台controller方法时报415 (Unsupported Media Type)错误
错误:ajax的post方法调用后台controller方法时报错:415 (Unsupported Media Type)。下面是错误时的代码
前端:
var url =“xxx/xxQuery.action”;
var params={
year:‘2017’
}
ajax(url,params,function(result){
console.log(result);
})
- 1
function ajax(url,params,callback,contentType){
var ajaxoptions={
url:url,
data:params,
type:“POST”,
dataType:“json”,
// contentType:",//application/x-www-form-urlencoded application/json"
success:function(res){
callback(res);
},
error:function(){
callback({success:false,description:“失败”}); }
}
if(contentType!=undefined){
ajaxoptions=$.extend(ajaxoptions,{contentType:contentType})
}
$.ajax(ajaxoptions);
- 1
}
var url =“xxx/xxQuery.action”;
var params={
year:‘2017’
}
ajax(url,params,function(result){
console.log(result);
})
- 1
function ajax(url,params,callback,contentType){
var ajaxoptions={
url:url,
data:params,
type:“POST”,
dataType:“json”,
// contentType:",//application/x-www-form-urlencoded application/json"
success:function(res){
callback(res);
},
error:function(){
callback({success:false,description:“失败”}); }
}
if(contentType!=undefined){
ajaxoptions=$.extend(ajaxoptions,{contentType:contentType})
}
$.ajax(ajaxoptions);
- 1
}
后台:
复制代码
@RequestMapping(value = { “/xxx/xxQuery.action” })
@ResponseBody
public Map<String, Object> xxQuery(Model model, HttpServletRequest request,
@RequestBody ORParameter parameter) {
........
return result;
}
- 1
- 2
- 3
复制代码
我的思路:对后台spring mvc不熟,只是有个概念服务器应该接收到了http请求,只是因为某种原因没有进入controller,而提前被拦截处理了。然后就开始找http处理的源头,笨办法,从HttpServlet.service开始找 -> DispatcherServlet.doDispatch,找到关键的处理方法handle
@Override
protected Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter methodParam,
Type paramType) throws IOException, HttpMediaTypeNotSupportedException {
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
HttpInputMessage inputMessage = new ServletServerHttpRequest(servletRequest);
RequestBody ann = methodParam.getParameterAnnotation(RequestBody.class);
if (!ann.required()) { //由于controller调用的这个方法参数加了@RequestBody,ann.required()这个为true就不走这里,
InputStream inputStream = inputMessage.getBody();
if (inputStream == null) {
return null;
}
else if (inputStream.markSupported()) {
inputStream.mark(1);
if (inputStream.read() == -1) {
return null;
}
inputStream.reset();
}
else {
final PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream);
int b = pushbackInputStream.read();
if (b == -1) {
return null;
}
else {
pushbackInputStream.unread(b);
}
inputMessage = new ServletServerHttpRequest(servletRequest) {
@Override
public InputStream getBody() {
// Form POST should not get here
return pushbackInputStream;
}
};
}
}
return super.readWithMessageConverters(inputMessage, methodParam, paramType);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
package org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver(类);
@SuppressWarnings(“unchecked”)
protected Object readWithMessageConverters(HttpInputMessage inputMessage,
MethodParameter methodParam, Type targetType) throws IOException, HttpMediaTypeNotSupportedException {
MediaType contentType;
try {
contentType = inputMessage.getHeaders().getContentType();
}
catch (InvalidMediaTypeException ex) {
throw new HttpMediaTypeNotSupportedException(ex.getMessage());
}
if (contentType == null) {
contentType = MediaType.APPLICATION_OCTET_STREAM;
}
Class<?> contextClass = methodParam.getDeclaringClass();
Map<TypeVariable, Type> map = GenericTypeResolver.getTypeVariableMap(contextClass);
Class<T> targetClass = (Class<T>) GenericTypeResolver.resolveType(targetType, map);
for (HttpMessageConverter<?> converter : this.messageConverters) {
if (converter instanceof GenericHttpMessageConverter) {
GenericHttpMessageConverter genericConverter = (GenericHttpMessageConverter) converter;
if (genericConverter.canRead(targetType, contextClass, contentType)) {
if (logger.isDebugEnabled()) {
logger.debug("Reading [" + targetType + "] as \"" +
contentType + "\" using [" + converter + "]");
}
return genericConverter.read(targetType, contextClass, inputMessage);
}
}
if (targetClass != null) {
if (converter.canRead(targetClass, contentType)) {
if (logger.isDebugEnabled()) {
logger.debug("Reading [" + targetClass.getName() + "] as \"" +
contentType + "\" using [" + converter + "]");
}
return ((HttpMessageConverter<T>) converter).read(targetClass, inputMessage);
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
//这里是报错位置
throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes);//没有找到参数对应的转换器就报错
}
原因:@RequestBody
a) 该注解用于读取Request请求的body部分数据,根据request的header部分的Content-Type类型,匹配HttpMessageConverter进行解析,然后把相应的数据绑定到要返回的对象上;
b) 再把HttpMessageConverter返回的对象数据绑定到 controller中方法的参数上。
前台没有注明后台解析参考的content-type,默认为application/x-www-form-urlencoded ,同时参数是对象也是不是json字符串,后台找不到解析方法。
解决:content-type为application/json格式的数据可以被jackson解读(这里在canread判断时用到),json对应jackson处理请求中的参数,jackson的参数应该是json字符串(enum JsonToken 这里有关于解析的字符串格式token的枚举内容: START_OBJECT("{")…), 而不是application/x-www-form-urlencoded编码的字符串“year=2017“。
所以前端请求需改为:
ajax(url,JSON.stringify(params),function(result){
console.log(result);
},"application/json")
- 1
- 2
- 3
正确解析时,调用的转换器是jackson。
备注:调用到参数解析的调用栈
可参考:https://blog.csdn.net/mingtianhaiyouwo/article/details/51445345
1.浏览器请求时没有设置Content-Type为Json,对于浏览器来说就是要把POST的内容放到jsonData属性中,而不是params。
2.第三方工具没有设置Content-Type的功能,默认的是Content-Type: application/x-www-form-urlencoded
@PostMapping("/run4")
public R<List<Empbole>> run4(@RequestBody BzydFzHonor bzydFzHono) throws Exception {
String userid = bzydFzHono.getUserid();
QueryWrapper<Empbole> empboleQueryWrapper = new QueryWrapper<>();
empboleQueryWrapper.eq("user_id",userid);
List<Empbole> userList = empboleService.list(empboleQueryWrapper);
return R.ok(userList);
}
function ajax(url, params, callback, contentType) {
var ajaxoptions = {
url: url,
data: params,
type: 'POST',
dataType: 'json',
success: function (res) {
callback(res);
},
error: function () {
callback({success: false, description: 'false'});
}
}
if (contentType != undefined) {
ajaxoptions = $.extend(ajaxoptions, {contentType: contentType})
}
$.ajax(ajaxoptions);
}
ajax("http://111.75.222.140:8084/empbole/run4",JSON.stringify(postData),function(result){
console.log(result);
},"application/json")
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
2021-09-27 Vue组件模板形式实现对象数组数据循环为树形结构(实例代码)
2021-09-27 打开画图工具命令
2021-09-27 github