请求路径不对,预检请求preflight返回404,导致真实请求返回CORS错误

14 篇文章 0 订阅
4 篇文章 0 订阅

目录

环境信息

问题描述

解决方案

解决思路

解决方法

不同的路径错误现象

上下文路径不对

chrome浏览器

网络

控制台

 火狐

网络

控制台

第一个请求:真实请求

第二个请求:预检请求preflight

非上下文的路径不对

chrome浏览器

控制台

第一个请求:预检请求preflight

第二个请求:真实请求

源码分析

调用链

CoyoteAdapter.java

Mapper.java

匹配逻辑

CoyoteAdapter.java

总结


环境信息

Spring Boot:2.0.8.RELEASE

Spring Boot内置的tomcat:tomcat-embed-core 8.5.37

问题描述

        在使用浏览器访问应用,给服务端发送请求的时候,前端没有收到正确的响应,浏览器控制台和网络都报错了:

解决方案

解决思路

        乍一看是CORS跨域问题,可是服务端已经进行了CORS跨域全部放行设置,莫非是不生效了或者被回退了。

按这个思路排查发现不是因为cors导致的,cors的跨域设置还是生效的。服务器也没问题,启动日志正常。

       后面仔细看了下报错信息,发现请求的url路径不大对,根路径不对!

 请求的正确路径是:

http://localhost:9003/tfb-remt-biz-service-app/trade/tradeService

备注:现实里发生的错误,请求路径不是图片里那样,而是

http://localhost:9003/remt-biz-service-app/trade/tradeService

为了使案例的错误明显些,将请求改成了

http://localhost:9003/tfb-remt-biz-service-app2/trade/tradeService

解决方法

将请求的路径改成正确的之后,成功收到服务端的返回信息。

不同的路径错误现象

        这次的错误,浏览器提示的信息很有误导性,印象中的路径不对应该是直接返回404,而不会出现CORS跨域错误。

为了深入了解预检请求preflight返回404,导致CORS跨域错误的原因,分析了下源码,并和普通的路径不对返回404进行了对比

上下文路径不对

如果是应用的上下文路径不对,比如tfb-remt-biz-service-app写成了tfb-remt-biz-service-app2

http://localhost:9003/tfb-remt-biz-service-app2/trade/tradeService

复杂请求的时候,会先发送预检请求,再发送真正的请求。

以下是2个请求的结果:

chrome浏览器

网络

只筛选Fetch/XHR:显示的结果是CORS错误,很容易被误导成CORS的设置有问题,比较难发现是404请求路径错误

 不筛选,显示全部网络请求:

控制台

 火狐

网络

控制台

第一个请求:真实请求

这个请求的真正处理是在预检请求preflight返回之后的。

返回的状态是CORS错误,而不是404

第二个请求:预检请求preflight

请求方法是OPTIONS,需要注意的是返回信息:响应体是空,响应头里没有包含了Access-Control-Allow-Origin,返回的状态是404

非上下文的路径不对

如果访问的url里,上下文路径是对的,后面的路径不对,比如tradeService写成了tradeService2,如下图所示;

http://localhost:9003/tfb-remt-biz-service-app/trade/tradeService2

复杂请求的时候,会先发送预检请求,再发送真正的请求

以下是2个请求的结果:

chrome浏览器

网络

注意如果有筛选了请求类型,要先去掉筛选,不然如果没有选中其他,那么预检请求(prefight)不会显示

控制台

第一个请求:预检请求preflight

请求方法是OPTIONS,需要注意的是返回信息:响应体是空,响应头里包含了Access-Control-Allow-Origin: http://localhost:9999,返回的状态是200

 服务端的请求处理链路:在CorsFilter里进行了跨域处理,因为服务端设置了允许跨域,因此响应头里包含了允许跨域Access-Control-Allow-Origin。

服务端跨域设置:

 服务端的请求处理链路: 

 

第二个请求:真实请求

因为找不到该路径对应的服务端接口,返回的状态是404

源码分析

调用链

CoyoteAdapter.java

在postParseRequest方法里执行了

            connector.getService().getMapper().map(serverName, decodedURI,
                    version, request.getMappingData());

这里的取得的mapper是 org.apache.catalina.mapper.Mapper

Mapper.java

contexts的值:

contexts= {Mapper$MappedContext[1]@24469} 
 0 = {Mapper$MappedContext@24470} 
  versions = {Mapper$ContextVersion[1]@24472} 
  name = "/tfb-remt-biz-service-app"
  object = null

 根据uri来和contexts上下文路径/根路径来进行匹配

根路径:/tfb-remt-biz-service-app

1.如果请求路径的上下文路径不对,比如:

http://localhost:9003/tfb-remt-biz-service-app2/trade/tradeService

那么匹配不到,found是false。

2.如果请求路径的上下文路径是对的,其余路径不对,比如:

http://localhost:9003/tfb-remt-biz-service-app/trade/tradeService2

那么是可以匹配到的,found是true。

匹配逻辑

        while (pos >= 0) {
            context = contexts[pos];
            if (uri.startsWith(context.name)) {
                length = context.name.length();
                if (uri.getLength() == length) {
                    found = true;
                    break;
                } else if (uri.startsWithIgnoreCase("/", length)) {
                    found = true;
                    break;
                }
            }
            if (lastSlash == -1) {
                lastSlash = nthSlash(uri, contextList.nesting + 1);
            } else {
                lastSlash = lastSlash(uri);
            }
            uri.setEnd(lastSlash);
            pos = find(contexts, uri);
        }

匹配不到,在这里返回了,没有往下执行

 

 下列的语句没有执行到,因此请求的上下文对象request.getContext()还是空的:

        mappingData.context = contextVersion.object;
        mappingData.contextSlashCount = contextVersion.slashCount;

CoyoteAdapter.java

执行完

            connector.getService().getMapper().map(serverName, decodedURI,
                    version, request.getMappingData());

之后,request.getContext() == null,直接返回了404,不再进行后续的处理,包括CORS过滤器,因此响应头里是没有Access-Control-Allow-Origin的

总结

        tomcat在处理请求(包括预检请求)的时候,会首先对请求的uri和服务的上下文路径/根路径进行匹配,

如果匹配到了,才继续进行后续的CORS过滤器等处理,并可能携带允许跨域的响应头,真实请求不会出现CORS;

如果匹配不到,那么直接返回404,不会携带允许跨域的响应头,造成了真实请求出现CORS错误,而不是404错误。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值