今天看了下源码,总结一下
说到这两个参数,不得不先回顾一下HTTP协议Header中的两个东西
ContentType 和Accept
在Request中
ContentType 用来告诉服务器当前发送的数据是什么格式
Accept 用来告诉服务器,客户端能认识哪些格式,最好返回这些格式中的其中一种
consumes 用来限制ContentType
produces 用来限制Accept
举例:
有个用户给我发了一个请求,
请求头中
ContentType =application/json
Accept = */*
就是说用户发送的json格式的数据,可以接收任意格式的数据返回
但是我的接口中定义了consumes={"application/xml"},produces={"application/xml"}
我只接收 application/xml 格式,也只返回xml格式
很明显,用户调不通这个接口
所以我改下consumes={"application/xml","application/json"},produces={"application/xml"}
注: 除了格式支持,还需要与数据对应的http转换器(HttpMessageConverter)此处先跳过
MediaType 其实就是 application/xml,application/json 等类型格式
接下来看下源码
AbstractHandlerMethodMapping
在这里通过查找符合类型的method
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { List<Match> matches = new ArrayList<Match>(); //这里找到所有对应path的方法 List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath); if (directPathMatches != null) { addMatchingMappings(directPathMatches, matches, request); } if (matches.isEmpty()) { // No choice but to go through all mappings... addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request); } if (!matches.isEmpty()) { Comparator<Match> comparator = new MatchComparator(getMappingComparator(request)); Collections.sort(matches, comparator); if (logger.isTraceEnabled()) { logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches); } Match bestMatch = matches.get(0); if (matches.size() > 1) { if (CorsUtils.isPreFlightRequest(request)) { return PREFLIGHT_AMBIGUOUS_MATCH; } Match secondBestMatch = matches.get(1); if (comparator.compare(bestMatch, secondBestMatch) == 0) { Method m1 = bestMatch.handlerMethod.getMethod(); Method m2 = secondBestMatch.handlerMethod.getMethod(); throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" + request.getRequestURL() + "': {" + m1 + ", " + m2 + "}"); } } handleMatch(bestMatch.mapping, lookupPath, request); return bestMatch.handlerMethod; } else { return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request); } } private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) { for (T mapping : mappings) { T match = getMatchingMapping(mapping, request); if (match != null) { matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping))); } } }
RequestMappingInfo
在这里对header,consumes和produces进行筛选
public RequestMappingInfo getMatchingCondition(HttpServletRequest request) { RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request); ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request); HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request); [color=red] ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request); ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);[/color] if (methods == null || params == null || headers == null || consumes == null || produces == null) { return null; } PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request); if (patterns == null) { return null; } RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request); if (custom == null) { return null; } return new RequestMappingInfo(this.name, patterns, methods, params, headers, consumes, produces, custom.getCondition()); }
ConsumesRequestCondition
对consume的过滤
public ConsumesRequestCondition getMatchingCondition(HttpServletRequest request) { if (CorsUtils.isPreFlightRequest(request)) { return PRE_FLIGHT_MATCH; } if (isEmpty()) { return this; } MediaType contentType; try { contentType = StringUtils.hasLength(request.getContentType()) ? MediaType.parseMediaType(request.getContentType()) : MediaType.APPLICATION_OCTET_STREAM; } catch (InvalidMediaTypeException ex) { return null; } Set<ConsumeMediaTypeExpression> result = new LinkedHashSet<ConsumeMediaTypeExpression>(this.expressions); for (Iterator<ConsumeMediaTypeExpression> iterator = result.iterator(); iterator.hasNext();) { ConsumeMediaTypeExpression expression = iterator.next(); if (!expression.match(contentType)) { iterator.remove(); } } return (result.isEmpty()) ? null : new ConsumesRequestCondition(result); }
ProducesRequestCondition
对Produces的过滤
public ProducesRequestCondition getMatchingCondition(HttpServletRequest request) { if (CorsUtils.isPreFlightRequest(request)) { return PRE_FLIGHT_MATCH; } if (isEmpty()) { return this; } List<MediaType> acceptedMediaTypes; try { //获取Accept acceptedMediaTypes = getAcceptedMediaTypes(request); } catch (HttpMediaTypeException ex) { return null; } Set<ProduceMediaTypeExpression> result = new LinkedHashSet<ProduceMediaTypeExpression>(expressions); for (Iterator<ProduceMediaTypeExpression> iterator = result.iterator(); iterator.hasNext();) { ProduceMediaTypeExpression expression = iterator.next(); if (!expression.match(acceptedMediaTypes)) { iterator.remove(); } } if (!result.isEmpty()) { return new ProducesRequestCondition(result, this.contentNegotiationManager); } else if (acceptedMediaTypes.contains(MediaType.ALL)) { return EMPTY_CONDITION; } else { return null; } }
从代码中可以清楚的看到consumes和produces的区别