ajax调用后台controller方法时报415 (Unsupported Media Type)错误

spring mvc ,ajax调用后台controller方法时报415 (Unsupported Media Type)错误

 

错误:ajax的post方法调用后台controller方法时报错:415 (Unsupported Media Type)。下面是错误时的代码

前端:

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

var url ="xxx/xxQuery.action";

var params={

            year:'2017'

        }                                              

    ajax(url,params,function(result){

            console.log(result);   

         

    })

 

 

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);

}

  

后台:

复制代码

@RequestMapping(value = { "/xxx/xxQuery.action" })
    @ResponseBody
    public Map<String, Object> xxQuery(Model model, HttpServletRequest request,
            @RequestBody ORParameter parameter) {

        ........
        return result;
    }

复制代码

我的思路:对后台spring mvc不熟,只是有个概念服务器应该接收到了http请求,只是因为某种原因没有进入controller,而提前被拦截处理了。然后就开始找http处理的源头,笨办法,从HttpServlet.service开始找 -> DispatcherServlet.doDispatch,找到关键的处理方法handle

抛出错误的位置

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

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

package org.springframework.web.servlet.mvc.method.annotation. RequestResponseBodyMethodProcessor;

 

@Override

    protected <T> 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);

    }

 

package org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver(类);

@SuppressWarnings("unchecked")

    protected <T> 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);

                }

            }

        }

          //这里是报错位置

        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")

 

  

正确解析时,调用的转换器是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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值