zoukankan      html  css  js  c++  java
  • Spring-web源码解析之ContentNegotiationStrategy

    创建ContentNegotiationStrategy组件源码,参考:org.springframework.web.accept.ContentNegotiationManagerFactoryBean#afterPropertiesSet

    Spring-web源码解析之ContentNegotiationStrategy

    基于4.1.7.RELEASE

    request和mediatypes解析的策略类,其唯一的一个接口是

    List<MediaType> resolveMediaTypes(NativeWebRequest webRequest) throws HttpMediaTypeNotAcceptableException;
    该接口负责将给与的request解析出对应的MediaType来,其实现有以下几种

    FixedContentNegotiationStrategy
    固定类型解析 : 返回固定的MediaType,每个类都有一个defaultContentType,在构造函数时需要传入默认的MediaType类型,其接口实现方式如下
    @Override
    public List<MediaType> resolveMediaTypes(NativeWebRequest webRequest) {
    return Collections.singletonList(this.defaultContentType);
    }

    HeaderContentNegotiationStrategy
    accept Header解析 : 负责解析request头中的accept,接口实现如下
    @Override
    public List<MediaType> resolveMediaTypes(NativeWebRequest webRequest) throws HttpMediaTypeNotAcceptableException {
    String acceptHeader = webRequest.getHeader(ACCEPT_HEADER);
    try {
    if (StringUtils.hasText(acceptHeader)) {
    List<MediaType> mediaTypes = MediaType.parseMediaTypes(acceptHeader);
    MediaType.sortBySpecificityAndQuality(mediaTypes);
    return mediaTypes;
    }
    }
    catch (InvalidMediaTypeException ex) {
    throw ;
    }
    return Collections.emptyList();
    }

    这里首先从request中取出Accept对应的字段,然后解析将其包装成MeidaType,排完序后返回MediaType列表。下面举例来说明:
    比如我有一个请求  Accept是这样  
    Accept:image/webp,image/*,*/*;q=0.8
    在上面的步骤中,首先会取出Accept对应的字段交给MediaType.parseMediaTypes进行包装,根据正则表达式 “ ,\s* ”进行分割,分割后字符串变成了如下形式[imgage/webp] [image/*] [*/*;q=0.8]
    然后逐个对数组元素进行判断,判断规则如下
    1 根据 “;” 符号进行拆分
    2 拆分出的第一部分再根据  “/“ 进行拆分
    3 判断步骤2中拆分出的两部分是否符合  */xxx 的模式,如果是,则抛出异常,这里只允许   */*,  xx/* , xx/xx  的模式 (type/subType)
    4 对步骤1中第二部分根据 ”=“ 号拆分,将其封装进MediaType的parameterMap中
    5 将步骤3中的type和subType封装进MediaType

    到此处理完毕之后就返回解析出的MediaTypes。

    ParameterContentNegotiationStrategy
    parameter解析 : 根据request中的参数来判断mediaType的类型,默认的参数名为format,在其构造函数中需要传递一个mediaType的Map,在解析format时,format对应的值就会在这个map里寻找匹配MediaType。其参数名可以使用setParameterName方法注入修改。
    举例: http://xxx.alibaba-inc.com/xx?format=json  时,会根据format的值json,去寻找json对应的MediaType类型。
    @Override
    protected String getMediaTypeKey(NativeWebRequest webRequest) {
    return webRequest.getParameter(this.parameterName);
    }

    根据MediaTypeKey去寻找MediaType。

    PathExtensionContentNegotiationStrategy
    路径名解析 : 根据请求路径的后缀名来判断用哪种MediaType,默认忽略未知的路径扩展名,比如说我们常见的 xx.html,xx.json ,里的.html,.json都是已知的路径扩展名,对于程序来说,只要没有匹配上就属于未知的扩展名。
    在寻找路径名匹配的过程中,如果在构造函数中的Map中没有找到MediaType,会采用JAF作为备用机制来查询MediaType。
    @Override
    protected String getMediaTypeKey(NativeWebRequest webRequest) {
    HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
    if (servletRequest == null) {
    return null;
    }
    String path = urlPathHelper.getLookupPathForRequest(servletRequest);
    String filename = WebUtils.extractFullFilenameFromUrlPath(path);
    String extension = StringUtils.getFilenameExtension(filename);
    return (StringUtils.hasText(extension)) ? extension.toLowerCase(Locale.ENGLISH) : null;
    }

    根据MediaTypeKey去寻找MediaType。

    ServletPathExtensionContentNegotiationStrategy
    属于4的扩展,作为4的一种备用机制使用ServletContext.getMIMEType来匹配MediaType,备用机制的实现是在handlerNoMatch方法里,如果是application/octet-stream类型(比如上传文件),则不采用该备用机制。

    总结:4种策略  固定类型,accept Header解析,parameter解析,路径扩展名解析。
    ————————————————
    版权声明:本文为CSDN博主「子沭」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/ktlifeng/article/details/50570128

    SpringMVC源码解析-ContentNegotiationStrategy

    说白了,这个接口就是想知道你(客户端)需要什么类型(MediaType)的数据。不是针对Content-Type的,因为没有解析charset。

    /**
    * 处理请求中的媒体类型的策略接口
    */
    public interface ContentNegotiationStrategy {
    /**
    * 将给定的请求解析为媒体类型列表
    * 返回的 List 首先按照 specificity 参数排序,其次按照 quality 参数排序
    *
    * webRequest: 当前的请求
    * 返回请求的媒体类型或者是一个空的 List
    * 如果请求的媒体类型不能被解析则抛出 HttpMediaTypeNotAcceptableException 异常
    */
    List<MediaType> resolveMediaTypes(NativeWebRequest webRequest)
    throws HttpMediaTypeNotAcceptableException;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16


    SpringMVC 默认加载两个该接口的实现类:
    ServletPathExtensionContentNegotiationStrategy–根据文件扩展名。
    HeaderContentNegotiationStrategy–根据HTTP Header里的Accept字段。

    HeaderContentNegotiationStrategy 负责解析Http Request Header中的Accept

    /**
    * 检查请求头 Accept 的 ContentNegotiationStrategy 的实现类
    */
    public class HeaderContentNegotiationStrategy implements ContentNegotiationStrategy {

    /**
    * 如果 Accept 请求头不能被解析则抛出 HttpMediaTypeNotAcceptableException 异常
    */
    @Override
    public List<MediaType> resolveMediaTypes(NativeWebRequest request)
    throws HttpMediaTypeNotAcceptableException {
    //获得请求头 Accept 的值
    // 形如: "Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"
    String[] headerValueArray = request.getHeaderValues(HttpHeaders.ACCEPT);
    if (headerValueArray == null) {
    return Collections.<MediaType>emptyList();
    }

    List<String> headerValues = Arrays.asList(headerValueArray);
    try {
    // 将上述媒体类型组成的字符串分离出来
    List<MediaType> mediaTypes = MediaType.parseMediaTypes(headerValues);
    // 将媒体类型排序
    MediaType.sortBySpecificityAndQuality(mediaTypes);
    return mediaTypes;
    }
    catch (InvalidMediaTypeException ex) {
    throw new HttpMediaTypeNotAcceptableException(
    "Could not parse 'Accept' header " + headerValues + ": " + ex.getMessage());
    }
    }

    }
    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
    调用关系:


    private final ContentNegotiationManager contentNegotiationManager;
    contentNegotiationManager 保存了ContentNegotiationStrategy 的实现类
    private final List<ContentNegotiationStrategy> strategies = new ArrayList<ContentNegotiationStrategy>();

    同时也可以看到如果没有传递Accept,则默认使用MediaType.ALL 也就是*/*

    参考:
    http://blog.csdn.net/ktlifeng/article/details/50570128


    ————————————————
    版权声明:本文为CSDN博主「N3verL4nd」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/x_iya/article/details/78114101

  • 相关阅读:
    状态压缩DP------学习小记
    hdu 4681 string
    poj 3254 Corn Fields
    poj 3680 Intervals
    poj 1149 pigs ---- 最大流
    最大流算法----(SAP 和 EK)
    poj 2151 Check the difficulty of problems
    FTP的PORT(主动模式)和PASV(被动模式)
    json.stringify(),json.stringify()与json.parse()的区别
    css 选择器
  • 原文地址:https://www.cnblogs.com/hfultrastrong/p/12175259.html
Copyright © 2011-2022 走看看