今天看了下源码,总结一下
说到这两个参数,不得不先回顾一下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 = (lookupPath);
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
if (()) {
// No choice but to go through all mappings...
addMatchingMappings(().keySet(), matches, request);
}
if (!()) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
(matches, comparator);
if (()) {
("Found " + () + " matching mapping(s) for [" +
lookupPath + "] : " + matches);
}
Match bestMatch = (0);
if (() > 1) {
if ((request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
Match secondBestMatch = (1);
if ((bestMatch, secondBestMatch) == 0) {
Method m1 = ();
Method m2 = ();
throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +
() + "': {" + m1 + ", " + m2 + "}");
}
}
handleMatch(, lookupPath, request);
return ;
}
else {
return handleNoMatch(().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) {
(new Match(match, ().get(mapping)));
}
}
}
RequestMappingInfo
在这里对header,consumes和produces进行筛选
public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
RequestMethodsRequestCondition methods = (request);
ParamsRequestCondition params = (request);
HeadersRequestCondition headers = (request);
[color=red] ConsumesRequestCondition consumes = (request);
ProducesRequestCondition produces = (request);[/color]
if (methods == null || params == null || headers == null || consumes == null || produces == null) {
return null;
}
PatternsRequestCondition patterns = (request);
if (patterns == null) {
return null;
}
RequestConditionHolder custom = (request);
if (custom == null) {
return null;
}
return new RequestMappingInfo(, patterns,
methods, params, headers, consumes, produces, ());
}
ConsumesRequestCondition
对consume的过滤
public ConsumesRequestCondition getMatchingCondition(HttpServletRequest request) {
if ((request)) {
return PRE_FLIGHT_MATCH;
}
if (isEmpty()) {
return this;
}
MediaType contentType;
try {
contentType = (()) ?
(()) :
MediaType.APPLICATION_OCTET_STREAM;
}
catch (InvalidMediaTypeException ex) {
return null;
}
Set<ConsumeMediaTypeExpression> result = new LinkedHashSet<ConsumeMediaTypeExpression>();
for (Iterator<ConsumeMediaTypeExpression> iterator = (); ();) {
ConsumeMediaTypeExpression expression = ();
if (!(contentType)) {
();
}
}
return (()) ? null : new ConsumesRequestCondition(result);
}
ProducesRequestCondition
对Produces的过滤
public ProducesRequestCondition getMatchingCondition(HttpServletRequest request) {
if ((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 = (); ();) {
ProduceMediaTypeExpression expression = ();
if (!(acceptedMediaTypes)) {
();
}
}
if (!()) {
return new ProducesRequestCondition(result, );
}
else if (()) {
return EMPTY_CONDITION;
}
else {
return null;
}
}
从代码中可以清楚的看到consumes和produces的区别