九、响应处理——内容协商底层原理

响应处理——内容协商底层原理

  在前边学习返回值解析器时,里边使用了各种 MessageConverter 寻找哪个解析器可以处理我们的返回值,在寻找过程中,非常关键的一步就是内容协商,它通过遍历所有的 MessageConverter 一个一个寻找,接下来,就来看一下整个内容协商的流程。

  内容协商:根据客户端接收能力不同,返回不同媒体类型的数据。

  接下来,我们使用postman发起请求,分别测试返回json和xml的情况

在这里插入图片描述
先以application/xml来测试
在这里插入图片描述
前边的请求处理已经很熟悉了,直接下一步来到 ServletInvocableHandlerMethod.class
先拿到返回值

在这里插入图片描述
我们的请求标注了@ResponseBody,所以下一步就是找到能处理@ResponseBody的Handler,进过寻找,最终找到了 RequestResponseBodyMethodProcessor

在这里插入图片描述
step into 进入 writeWithMessageConverters,来到我们的内容协商关键环节

        //......代码太多没有全部拿
        MediaType selectedMediaType = null;
        //首先判断当前响应头中是否已经有确定的媒体类型MediaType,我们没有前置拦截,所以没有
        MediaType contentType = outputMessage.getHeaders().getContentType();
        boolean isContentTypePreset = contentType != null && contentType.isConcrete();
        if (isContentTypePreset) {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Found 'Content-Type:" + contentType + "' in response");
            }
			//如果有的话,就用之前的,我们没有走下边
            selectedMediaType = contentType;
        } else {
            HttpServletRequest request = inputMessage.getServletRequest();
            //关键来啦,第一步,获取客户端可接收的媒体类型(accept请求头字段)
            List<MediaType> acceptableTypes = this.getAcceptableMediaTypes(request);

这里step into进入看一下是如何获取 acceptableTypes
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
到这里,就获取到了客户端能接收的值 acceptableTypes 是我们传的 application/xml

			//然后获取能产生的媒体类型(写出类型) producibleTypes
            List<MediaType> producibleTypes = this.getProducibleMediaTypes(request, valueType, (Type)targetType);

这里step into进入看一下是如何获取 producibleTypes
在这里插入图片描述

            if (body != null && producibleTypes.isEmpty()) {
                throw new HttpMessageNotWritableException("No converter found for return value of type: " + valueType);
            }

            List<MediaType> mediaTypesToUse = new ArrayList();
            Iterator var15 = acceptableTypes.iterator();
			//得到客户端需要类型和服务端能处理的类型后,进行最佳匹配,双重循环
            MediaType mediaType;
            while(var15.hasNext()) {
                mediaType = (MediaType)var15.next();
                Iterator var17 = producibleTypes.iterator();

                while(var17.hasNext()) {
                    MediaType producibleType = (MediaType)var17.next();
                    if (mediaType.isCompatibleWith(producibleType)) {
                        mediaTypesToUse.add(this.getMostSpecificMediaType(mediaType, producibleType));
                    }
                }
            }

//.................中间省略处理代码.....................
		//拿到我们的对象
        body = this.getAdvice().beforeBodyWrite(body, returnType, selectedMediaType, converter.getClass(), inputMessage, outputMessage);
        if (body != null) {
            LogFormatUtils.traceDebug(this.logger, (traceOn) -> {
                return "Writing [" + LogFormatUtils.formatValue(body, !traceOn) + "]";
            });
            this.addContentDispositionHeader(inputMessage, outputMessage);
            if (genericConverter != null) {
            	//用 支持 将对象转为 最佳匹配媒体类型 的converter。调用它进行转化写出
                genericConverter.write(body, (Type)targetType, selectedMediaType, outputMessage);
            } else {
                converter.write(body, selectedMediaType, outputMessage);
            }
        } else if (this.logger.isDebugEnabled()) {
            this.logger.debug("Nothing to write: null body");
        }

用最佳converter转化写出
在这里插入图片描述
进入 AbstractJackson2HttpMessageConverter.classwriteValue 方法

在这里插入图片描述
完成之后来到了 write 方法最后一行,看 outputMessage
在这里插入图片描述
到这里,我们的内容协商环节就结束了,可以将 Accept 改成 application/json 调试练习。

OVER(∩_∩)O~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Anton丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值