V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
cpstar
V2EX  ›  问与答

CORS 和 JQUERY POST 打架了怎么办?求个解决之道

  •  
  •   cpstar · 2022-06-23 12:15:39 +08:00 · 1363 次点击
    这是一个创建于 917 天前的主题,其中的信息可能已经有所发展或是发生改变。

    昨天折腾发现了一个问题,脑袋一热,没找到根源就发了帖子 https://www.v2ex.com/t/861503 ,最后发现是 CORS 的问题。但是新的问题又来了。

    使用的是 Tomcat 8.5 ,用了官方的 CORS 。其中有一段代码是这样的

    } else if ("POST".equals(method)) {
        String mediaType = getMediaType(request.getContentType());
        if (mediaType != null) {
            if (SIMPLE_HTTP_REQUEST_CONTENT_TYPE_VALUES.contains(mediaType)) {
                requestType = CORSRequestType.SIMPLE;
            } else {
                requestType = CORSRequestType.ACTUAL;
            }
        }
    } else {
    
    

    其中 SIMPLE_HTTP_REQUEST_CONTENT_TYPE_VALUES 是 application/x-www-form-urlencoded, multipart/form-data, text/plain 其中之一; CORSRequestType 默认是 INVALID_CORS ,也就是返回 403 的情况。

    所以结论就是如果 POST 方法,Header 没有 Content-Type ,mediaType==null ,则走向了 403 ,解释了原帖的疑惑。可是问题根源在哪里呢?

    系统使用了比较古老的 JQuery 1.12 ,其中的片段是这样的:

    // Set the correct header, if data is being sent
    if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
    	jqXHR.setRequestHeader( "Content-Type", s.contentType );
    }
    

    这就是如果 data=="",那就不设置 Content-Type 。另外,POST 通过 querystring 提供了一些数据,所以 s.hasContent==true 。

    一个驴唇,一个马嘴,还真对上了🤣。一个是 POST 不见 Content-Type 就觉得不安全,一个是没有实际 data 就不搞 Content-Type 。而实际上 POST 是可以没有内容以及没有 Content-Type 的吧。

    那么怎么解决呢??

    • 修改 CORSFilter ?我认为这可能是一个 BUG ,因为这个 mediaType 的 if 没有 else ,或者原本的计划就是不能缺失 Content-Type ,缺失则是 403 。如果这里有问题,那就直接加上 else requestType = CORSRequestType.ACTUAL 重新编译然后注入到 Tomcat 里。
    • 修改 JQuery ?不知道新版 JQuery 如何认知这件事情的。可以搞一个拦截,比如 jquery 代码片段那里的 s.data 改成(true||s.data)。

    CORS 和 JQUERY 两方的原则是啥?改谁?

    9 条回复    2022-06-26 15:05:24 +08:00
    Rache1
        1
    Rache1  
       2022-06-23 12:40:29 +08:00   ❤️ 1
    有没有一种可能,就是「 jQuery 可以自行设置 Content-Type 」。
    renmu123
        2
    renmu123  
       2022-06-23 12:43:56 +08:00 via Android
    你 p 可以 ost 的时候指定一下 header
    renmu123
        3
    renmu123  
       2022-06-23 12:44:14 +08:00 via Android
    可以 post
    cpstar
        4
    cpstar  
    OP
       2022-06-23 13:44:23 +08:00
    @Rache1 1#
    @renmu123 2#
    这个还是某种程度上改 jquery 。有一个前提忘了提,这是一个相对稳定全面的框架,只能用一些釜底抽薪的方法。单独 js 和嵌在 html 里的 js 可能上百个,如果“正道”地改,那基本等于重写了。
    Rache1
        5
    Rache1  
       2022-06-23 14:02:56 +08:00   ❤️ 1
    @cpstar jQuery 提供了 $.ajaxPrefilter
    cpstar
        6
    cpstar  
    OP
       2022-06-23 14:37:43 +08:00
    @Rache1 5# 查了查,试了试,这个相当于全局的开关。甭管二次封装的,还是原生的$.ajax ,全都过滤一遍。标给治好了。
    另外就是好奇,这个驴唇和马嘴,各自有各自的思路?但是我觉得总该有一个统一的设置原则吧。
    Rache1
        7
    Rache1  
       2022-06-24 09:17:30 +08:00
    @cpstar CORS 没有完全限制服务端该怎么做,只是引导了服务端在什么情况下应该怎么做,比如发送 Cookie 时,需要允许认证和 Origin 需要返回对应域,在其他情况下,直接返回 * 都是可以的,所以对于服务端而言就相对自由。
    phy25
        8
    phy25  
       2022-06-26 13:15:36 +08:00
    https://fetch.spec.whatwg.org/#content-type-header

    > When extract a MIME type returns failure or a MIME type whose essence is incorrect for a given format, treat this as a fatal error.


    https://bugs.jquery.com/ticket/6674

    https://bugs.jquery.com/ticket/6811
    cpstar
        9
    cpstar  
    OP
       2022-06-26 15:05:24 +08:00
    @phy25 8#

    后边那两个 BUG 做了修正,但是不知道是哪个分支,查最新的 github 库上的代码(以及 1.12.stable 分支),跟我这个老掉牙的 1.12.4 确实是一种判断逻辑。

    至于第一个 spec ,好像只是提到了 MIME 的判断,跟 CORS 没啥关系。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5551 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 08:12 · PVG 16:12 · LAX 00:12 · JFK 03:12
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.