SpringBoot实战笔记:记一次接口406错误的解决

背景

  在对一个遗留老系统使用SpringBoot框架进行重写的过程中,遇到了一个奇怪的问题:即当服务使用SpringBoot的main入口独立启动的时候,接口访问一切正常,但是当项目被打成war包运行在Tomcat中时,调用接口就会返回406 Not Acceptable错误,而由于运维等层面考虑,服务仍然要在Tomcat中运行一段时间作为过渡,因此不管是从对技术追求的态度上,还是从实际需求出发,这都是个不得不解决的问题。

错误原因分析

  要解决问题,首先我们需要知道,406错误出现的直接原因是什么。在一次HTTP请求中,如果服务端对于body内容的类型(即Content-Type)处理上产生了冲突,即会返回406错误状态。

  SpringBoot处理Content-Type的具体代码入口在
org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor的方法writeWithMessageConverters中,其中一段如下:

HttpServletRequest request = inputMessage.getServletRequest();
List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(request);
List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType);

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

Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>();
for (MediaType requestedType : requestedMediaTypes) {
    for (MediaType producibleType : producibleMediaTypes) {
        if (requestedType.isCompatibleWith(producibleType)) {
            compatibleMediaTypes.add(getMostSpecificMediaType(requestedType, producibleType));
        }
    }
}
if (compatibleMediaTypes.isEmpty()) {
    if (outputValue != null) {
        throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes);
    }
    return;
}

 

可看到,其逻辑是,在当前请求可选的MediaType和接口要生成的MediaType中进行匹配,如果匹配不到,即会抛出HttpMediaTypeNotAcceptableException异常从而导致返回406错误。回到我们的项目,接口都是@RestController注解,因此producibleMediaTypes只能是application/json这一类,所以我们需要看requestedMediaTypes是什么。

  继续深入源码,getAcceptableMediaTypes方法如下:

private List<MediaType> getAcceptableMediaTypes(HttpServletRequest request) throws HttpMediaTypeNotAcceptableException {
    List<MediaType> mediaTypes = this.conte
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值