博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
406 Not Acceptable 415 Unsupported Media Type Spring MVC consumes与produces
阅读量:4229 次
发布时间:2019-05-26

本文共 13013 字,大约阅读时间需要 43 分钟。

        引言:SpringWeb MVC框架在使用的过程中,有时候会出现请求结果报406 Not Acceptable 或者415 Unsupported Media Type的错误,现在学习下为什么报这个错误以及怎么解决。

     Http协议基础知识及概念:

    HTTP(HyperText Transport Protocol)是超文本传输协议的缩写,是客户端浏览器或其他程序与器之间的应用层通信协议,关于HTTP协议的详细内容请参考RFC2616。通常HTTP消息包括客户机向服务器的请求消息和服务器向客户机的响应消息,请求消息包含请求行,头信息,实体(可能为空),响应消息包含状态行,头信息,实体。HTTP的头域包括通用头,请求头,响应头和实体头四个部分。通用头域包含请求和响应消息都支持的头域,通用头域包含Cache-Control、Connection、Date、Pragma、Transfer-Encoding、Upgrade、Via。对通用头域的扩展要求通讯双方都支持此扩展,如果存在不支持的通用头域,一般将会作为实体头域处理。

  通用头域:

         Cache-Control头域  指定请求和响应遵循的缓存机制

         Keep-Alive  Keep-Alive功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive功能避免了建立或者重新建立连接

        Date 表示消息发送的时间,时间的描述格式由rfc822定义。例如,Date:Mon,31Dec200104:25:57GMT。Date描述的时间表示世界标准时,换算成本地时间,需要知道用户所在的时区

       Pragma 用来包含实现特定的指令,最常用的是Pragma:no-cache。在HTTP/1.1协议中,它的含义和Cache-Control:no-cache相同

   请求头域:

      请求头域可能包含下列字段Accept、Accept-Charset、Accept-Encoding、Accept-Language、Authorization、From、Host、If-Modified-Since、If-Match、If-None-Match、If-Range、If-Range、If-Unmodified-Since、Max-Forwards、Proxy-Authorization、Range、Referer、User-Agent。对请求头域的扩展要求通讯双方都支持,如果存在不支持的请求头域,一般将会作为实体头域处理。

  响应头域:

    响应头域允许服务器传递不能放在状态行的附加信息,这些域主要描述服务器的信息和Request-URI进一步的信息。响应头域包含Age、Location、Proxy-Authenticate、Public、Retry-After、Server、Vary、Warning、WWW-Authenticate。

  实体头域:

    请求消息和响应消息都可以包含实体信息,实体信息一般由实体头域和实体组成。实体头域包含关于实体的原信息,实体头包括Allow、Content-Base、Content-Encoding、Content-Language、Content-Length、Content-Location、Content-MD5、Content-Range、Content-Type、Etag、Expires、Last-Modified、extension-header。extension-header允许客户端定义新的实体头,但是这些域可能无法被接受方识别。实体可以是一个经过编码的字节流,它的编码方式由Content-Encoding或Content-Type定义,它的长度由Content-Length或Content-Range定义。

    Http协议消息头 Content-Type和Accept

    Http协议的通信标准可以在RFC2616文件中有详细的说明,说明如下:

    Accept

14.1 Accept   The Accept request-header field can be used to specify certain media   types which are acceptable for the response. Accept headers can be   used to indicate that the request is specifically limited to a small   set of desired types, as in the case of a request for an in-line   image.       Accept         = "Accept" ":"                        #( media-range [ accept-params ] )       media-range    = ( "*/*"                        | ( type "/" "*" )                        | ( type "/" subtype )                        ) *( ";" parameter )       accept-params  = ";" "q" "=" qvalue *( accept-extension )       accept-extension = ";" token [ "=" ( token | quoted-string ) ]   The asterisk "*" character is used to group media types into ranges,   with "*/*" indicating all media types and "type/*" indicating all   subtypes of that type. The media-range MAY include media type   parameters that are applicable to that range.   Each media-range MAY be followed by one or more accept-params,   beginning with the "q" parameter for indicating a relative quality   factor. The first "q" parameter (if any) separates the media-range   parameter(s) from the accept-params. Quality factors allow the user   or user agent to indicate the relative degree of preference for that   media-range, using the qvalue scale from 0 to 1 (section 3.9). The   default value is q=1.      Note: Use of the "q" parameter name to separate media type      parameters from Accept extension parameters is due to historical      practice. Although this prevents any media type parameter named      "q" from being used with a media range, such an event is believed      to be unlikely given the lack of any "q" parameters in the IANA      media type registry and the rare usage of any media type      parameters in Accept. Future media types are discouraged from      registering any parameter named "q".Fielding, et al.            Standards Track                   [Page 100] RFC 2616                        HTTP/1.1                       June 1999   The example       Accept: audio/*; q=0.2, audio/basic   SHOULD be interpreted as "I prefer audio/basic, but send me any audio   type if it is the best available after an 80% mark-down in quality."   If no Accept header field is present, then it is assumed that the   client accepts all media types. If an Accept header field is present,   and if the server cannot send a response which is acceptable   according to the combined Accept field value, then the server SHOULD   send a 406 (not acceptable) response.   A more elaborate example is       Accept: text/plain; q=0.5, text/html,               text/x-dvi; q=0.8, text/x-c   Verbally, this would be interpreted as "text/html and text/x-c are   the preferred media types, but if they do not exist, then send the   text/x-dvi entity, and if that does not exist, send the text/plain   entity."   Media ranges can be overridden by more specific media ranges or   specific media types. If more than one media range applies to a given   type, the most specific reference has precedence. For example,       Accept: text/*, text/html, text/html;level=1, */*   have the following precedence:       1) text/html;level=1       2) text/html       3) text/*       4) */*   The media type quality factor associated with a given type is   determined by finding the media range with the highest precedence   which matches that type. For example,       Accept: text/*;q=0.3, text/html;q=0.7, text/html;level=1,               text/html;level=2;q=0.4, */*;q=0.5   would cause the following values to be associated:       text/html;level=1         = 1       text/html                 = 0.7       text/plain                = 0.3Fielding, et al.            Standards Track                   [Page 101] RFC 2616                        HTTP/1.1                       June 1999       image/jpeg                = 0.5       text/html;level=2         = 0.4       text/html;level=3         = 0.7      Note: A user agent might be provided with a default set of quality      values for certain media ranges. However, unless the user agent is      a closed system which cannot interact with other rendering agents,      this default set ought to be configurable by the user.

详细的中文大家可以网上翻译,大致的意思就是Accept请求头域可以被用来指定响应可接受的媒体类型,Accept请求头域用来表明请求被明确地限制到一个小的需要的类型集合内,正如一个请求内嵌图片的情况。在指定格式的同时还可以通过q参数指定权重。

406 Not Acceptable

The resource identified by the request is only capable of generating   response entities which have content characteristics not acceptable   according to the accept headers sent in the request.   Unless it was a HEAD request, the response SHOULD include an entity   containing a list of available entity characteristics and location(s)   from which the user or user agent can choose the one most   appropriate. The entity format is specified by the media type given   in the Content-Type header field. Depending upon the format and the   capabilities of the user agent, selection of the most appropriate   choice MAY be performed automatically. However, this specification   does not define any standard for such automatic selection.      Note: HTTP/1.1 servers are allowed to return responses which are      not acceptable according to the accept headers sent in the      request. In some cases, this may even be preferable to sending a      406 response. User agents are encouraged to inspect the headers of      an incoming response to determine if it is acceptable.   If the response could be unacceptable, a user agent SHOULD   temporarily stop receipt of more data and query the user for a   decision on further actions.

    大致的意思是请求指定的资源生产的带有内容的响应实体特性根据请求中发送来的Accept头域是不可接受的。如果响应不能被接受,客户端应该临时停止接受更多的数据并且为用户查询更进一步操作的决定。简而言之就是response设置的content-type不在请求头Accept指定的范围内。

415 Unsupported Media Type

The server is refusing to service the request because the entity of   the request is in a format not supported by the requested resource   for the requested method.

大致的意思是服务器正在拒绝为请求服务,因为请求的实体的格式不被请求的资源的方法支持,简而言之就是服务器的处理方法不支持请求实体中的content-type类型。

SpringMVC consumes与produces

    consumes

    RequestMapping注解中参数,源码注解如下:

/**	 * The consumable media types of the mapped request, narrowing the primary mapping.	 * 

The format is a single media type or a sequence of media types, * with a request only mapped if the {@code Content-Type} matches one of these media types. * Examples: *

	 * consumes = "text/plain"	 * consumes = {"text/plain", "application/*"}	 * 
* Expressions can be negated by using the "!" operator, as in "!text/plain", which matches * all requests with a {@code Content-Type} other than "text/plain". *

Supported at the type level as well as at the method level! * When used at the type level, all method-level mappings override * this consumes restriction. * @see org.springframework.http.MediaType * @see javax.servlet.http.HttpServletRequest#getContentType() */ String[] consumes() default {};

大致的意思是映射的请求可消费的媒体类型,缩小基本的映射。格式为一个或者一系列的媒体类型,只有请求的content-type匹配上这些媒体类型中的一个这个请求才算映射上了。

Spring MVC中,在从HandlerMapping中找到一个对应的处理链的时候,会检查该配置。在RequestMappingInfoHandlerMapping中handleNoMatch方法中有如下代码:

if (helper.hasConsumesMismatch()) {			Set
mediaTypes = helper.getConsumableMediaTypes(); MediaType contentType = null; if (StringUtils.hasLength(request.getContentType())) { try { contentType = MediaType.parseMediaType(request.getContentType()); } catch (InvalidMediaTypeException ex) { throw new HttpMediaTypeNotSupportedException(ex.getMessage()); } } throw new HttpMediaTypeNotSupportedException(contentType, new ArrayList
(mediaTypes)); }

在没有匹配上的时候会抛出HttpMediaTypeNotSupportedException,而这个异常会被Spring MVC在最后DefaultHandlerExceptionResolver中封装为415错误码的异常页面,源码如下:

/**	 * Handle the case where no {@linkplain org.springframework.http.converter.HttpMessageConverter message converters}	 * were found for the PUT or POSTed content.	 * 

The default implementation sends an HTTP 415 error, sets the "Accept" header, * and returns an empty {@code ModelAndView}. Alternatively, a fallback view could * be chosen, or the HttpMediaTypeNotSupportedException could be rethrown as-is. * @param ex the HttpMediaTypeNotSupportedException to be handled * @param request current HTTP request * @param response current HTTP response * @param handler the executed handler * @return an empty ModelAndView indicating the exception was handled * @throws IOException potentially thrown from response.sendError() */ protected ModelAndView handleHttpMediaTypeNotSupported(HttpMediaTypeNotSupportedException ex, HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException { response.sendError(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE); List

mediaTypes = ex.getSupportedMediaTypes(); if (!CollectionUtils.isEmpty(mediaTypes)) { response.setHeader("Accept", MediaType.toString(mediaTypes)); } return new ModelAndView(); }

返回的错误页面如下: 

produces

requestMapping注解参数,注释如下:

/**	 * The producible media types of the mapped request, narrowing the primary mapping.	 * 

The format is a single media type or a sequence of media types, * with a request only mapped if the {@code Accept} matches one of these media types. * Examples: *

	 * produces = "text/plain"	 * produces = {"text/plain", "application/*"}	 * produces = "application/json; charset=UTF-8"	 * 
*

It affects the actual content type written, for example to produce a JSON response * with UTF-8 encoding, {@code "application/json; charset=UTF-8"} should be used. *

Expressions can be negated by using the "!" operator, as in "!text/plain", which matches * all requests with a {@code Accept} other than "text/plain". *

Supported at the type level as well as at the method level! * When used at the type level, all method-level mappings override * this produces restriction. * @see org.springframework.http.MediaType */ String[] produces() default {};

匹配的请求资源可生产的媒体类型,限制基本的映射。格式是一个或者一系列的媒体类型,只有一个请求的Accept头中的媒体类型匹配到这个参数指定的媒体类型中的至少一个,才算请求匹配上了。这个参数还影响了实际的响应实体的类型。同理,在SpringMVC中也会检查该配置参数与实际请求的匹配情况,也是在RequestMappingInfoHandlerMapping中handleNoMatch方法中有如下代码:

if (helper.hasProducesMismatch()) {			Set
mediaTypes = helper.getProducibleMediaTypes(); throw new HttpMediaTypeNotAcceptableException(new ArrayList
(mediaTypes)); }

在DefaultHandlerExceptionResolver中也会封装该异常为406结果页面

/**	 * Handle the case where no {@linkplain org.springframework.http.converter.HttpMessageConverter message converters}	 * were found that were acceptable for the client (expressed via the {@code Accept} header.	 * 

The default implementation sends an HTTP 406 error and returns an empty {@code ModelAndView}. * Alternatively, a fallback view could be chosen, or the HttpMediaTypeNotAcceptableException * could be rethrown as-is. * @param ex the HttpMediaTypeNotAcceptableException to be handled * @param request current HTTP request * @param response current HTTP response * @param handler the executed handler * @return an empty ModelAndView indicating the exception was handled * @throws IOException potentially thrown from response.sendError() */ protected ModelAndView handleHttpMediaTypeNotAcceptable(HttpMediaTypeNotAcceptableException ex, HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException { response.sendError(HttpServletResponse.SC_NOT_ACCEPTABLE); return new ModelAndView(); }

转载地址:http://oasqi.baihongyu.com/

你可能感兴趣的文章
drop、truncate和delete的区别
查看>>
650. 2 Keys Keyboard
查看>>
651. 4 Keys Keyboard
查看>>
Https协议详解
查看>>
Linux相关的小知识点
查看>>
653. Two Sum IV - Input is a BST
查看>>
js插件的经典写法与总结
查看>>
bootstrap select2 动态改变值
查看>>
钉钉(工作协同)应用的前端源码
查看>>
正则表达式限定输入数字
查看>>
AngularJS Eclipse 插件
查看>>
Summernote实现图片上传功能
查看>>
Spring+MyBatis多数据源配置实现(mysql和sqlserver数据库)
查看>>
Java基于jxl与模板导出excel并弹出下载
查看>>
web/html5调用摄像头实现二维码扫描
查看>>
tomcat开机自启动
查看>>
WINDOWS中NEXUS的安装使用【ATCO整理】 2016-06-20 15:52 367人阅读 评论(0) 收藏 举报 分类: 项目管理(11) 版权声明:本文为博主原创文章,未经博主允许
查看>>
sql月份累加统计查询
查看>>
Google Translate API
查看>>
千万级PV网站架构
查看>>