关于 CORS 的一个问题,大家怎么看 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
mitu9527
V2EX    程序员

关于 CORS 的一个问题,大家怎么看

  •  1
     
  •   mitu9527 2020-09-02 17:28:15 +08:00 4308 次点击
    这是一个创建于 1914 天前的主题,其中的信息可能已经有所发展或是发生改变。

    昨天先去了解了下同源策略,然后又去看了一些和 CORS 相关的文章,几乎所有的文章都告诉我只要在响应头中加入几个 Access-Control-* 头部就可以了。比如像这样:

    header('Access-Control-Allow-Origin:http://www.startphp.cn'); header('Access-Control-Allow-Methods:POST'); header('Access-Control-Allow-Headers:x-requested-with, content-type'); 

    这段代码是我从别的地方复制过来的,不同文章的具体代码不一样,但都是差不多的,只不过多几个头部或者某个头部的值不一样罢了,没什么本质区别。

    服务端这样做确实可以通知客户端,让其拒绝服务端返回的响应,但是服务端关于 CORS 的全部工作就这些么?我觉得不是!至少还应该加一些处理,起码应该在适当的时候结束程序的执行,如果服务端都准备告诉客户端拒绝自己的响应了,那发完响应头部,就没必要再执行后续的业务逻辑了,不是么?反过来说,所有的逻辑都执行完了,然后你再加几个头部去告诉客户端把自己拒绝掉,这不是多此一举么?

    我知道客户端只要不发送 Origin 头部,就可以绕过服务端的 CORS 处理;我也知道要想提升安全性,必须得做鉴权才行,但就是觉得服务端的 CORS 处理这块还是应该稍微完善一点,不应该只是加几个头部就草草的结束了才对。如果你觉得我的这种想法是有问题且多余的,欢迎留言指正!

    最后我列出我的一点代码,代码并没有做过测试,也更没在开发环境和生产环境中使用过,只是想说明一下我觉得完善的 CORS 处理大概应该是什么样子。具体的逻辑主要参考的是阮一峰的这篇文章:《跨域资源共享 CORS 详解》 。有兴趣的伙伴可以去看看。

    <?php // CORS 配置 $cOnfig= [ 'allow_origin' => ["http://b.example.com", "http://c.example.com"], 'allow_method' => ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], 'allow_headers' => ['X-Custom-Header', 'Accept'], 'expose_headers' => ['Content-Range'], 'allow_credentials' => true, 'max_age' => 86400, ]; // CORS 预检请求 if (isCorsPreflightRequest()) { // 检查预检请求 if (checkCorsPreflightRequest($config)) { // 通过 addCorsPreflightRequestHeaders($config); } else { // 未通过,什么也不做 } // 退出,不进入业务逻辑部分 exit; } // CORS 简单请求 if (isCorsSimpleRequest()) { // 检查简单请求 if (checkCorsSimpleRequest($config)) { // 通过 addCorsSimpleRequestHeaders($config); } else { // 没通过,退出,不进入业务逻辑部分 exit; } } function isCorsPreflightRequest(): bool { return isset($_SERVER['HTTP_ORIGIN'], $_SERVER['REQUEST_METHOD']) && 'OPTIONS' === strtoupper($_SERVER['REQUEST_METHOD']); } function checkCorsPreflightRequest(array $config): bool { return checkCorsOrigin($config) && checkCorsRequestMethod($config) && checkCorsRequestHeaders($config); } function checkCorsOrigin(array $config): bool { return '*' === $config['allow_origin'] || in_array($_SERVER['HTTP_ORIGIN'], $config['allow_origin'], true); } function checkCorsRequestMethod(array $config): bool { if ( isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']) && !in_array(strtoupper($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']), $config['allow_method'], true) ) { return false; } return true; } function checkCorsRequestHeaders(array $config): bool { if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])) { $requestHeaders = explode(',', $_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']); $allowHeaders = array_map(fn($header) => strtoupper($header), $config['allow_headers']); foreach ($requestHeaders as $requestHeader) { $requestHeader = strtoupper(trim($requestHeader)); if (!in_array($requestHeader, $allowHeaders, true)) { return false; } } } return true; } function addCorsPreflightRequestHeaders(array $config): void { if ('*' === $config['allow_origin']) { header('Access-Control-Allow-Origin: *'); } else { header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']); } header('Access-Control-Allow-Methods: ' . implode(',', $config['allow_method'])); header('Access-Control-Allow-Headers: ' . implode(',', $config['allow_headers'])); header('Access-Control-Allow-Credentials: ' . ($config['allow_credentials'] ? 'true' : 'false')); header('Access-Control-Max-Age: ' . $config['max_age']); } function isCorsSimpleRequest(): bool { return isset($_SERVER['HTTP_ORIGIN']); } function checkCorsSimpleRequest(array $config): bool { return checkCorsOrigin($config); } function addCorsSimpleRequestHeaders(array $config, array $exposeHeaders = []): void { if ('*' === $config['allow_origin']) { header('Access-Control-Allow-Origin: *'); } else { header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']); } if (empty($exposeHeaders)) { header('Access-Control-Allow-Headers: ' . implode(',', $config['expose_headers'])); } else { header('Access-Control-Allow-Headers: ' . implode(',', $exposeHeaders)); } header('Access-Control-Allow-Credentials: ' . ($config['allow_credentials'] ? 'true' : 'false')); } // 假设下方是业务逻辑部分的代码 // 省略... 
    ssshooter
        1
    ssshooter  
       2020-09-02 17:38:19 +08:00   1
    服务端真的没有什么可以做的...CORS 完全只是浏览器定下的拦截约定
    mitu9527
        2
    mitu9527  
    OP
       2020-09-02 17:40:09 +08:00
    @ssshooter 明白,不过我觉得在已经知道请求会被拒绝的情况下,就别再去执行后续的代码了,有些多余。
    shintendo
        3
    shintendo  
       2020-09-02 17:43:00 +08:00   1
    浏览器可以关闭同源策略
    mitu9527
        4
    mitu9527  
    OP
       2020-09-02 17:52:53 +08:00
    @shintendo 我知道,但是我想说的不是这个。
    asiufasd
        5
    asiufasd  
       2020-09-02 18:16:23 +08:00
    我觉得你可以带着以下问题再次仔细阅读你列出的参考文章,我认为你没有从阅读的文章中得出正确的结论。
    1. “服务端这样做确实可以通知客户端,让其拒绝服务端返回的响应” ;跨域请求失败的响应头到底是什么样的?会带“Access-Control-*”吗?
    2. “如果服务端都准备告诉客户端拒绝自己的响应了,那发完响应头部,就没必要再执行后续的业务逻辑了” ;返回“Access-Control-* ”相应头是对应的什么请求,会执行具体的逻辑吗?(提示,options )
    mitu9527
        6
    mitu9527  
    OP
       2020-09-02 18:22:28 +08:00
    @asiufasd 我觉得我看明白了。你可以说完么,不要话说一半哈。
    lalalaqwer
        7
    lalalaqwer  
       2020-09-02 18:40:30 +08:00 via Android
    同源策略是浏览器的规则
    事实上存在跨域情况时,浏览器会先发送 option 预检请求,只有得到了服务器肯定的答复才会发送真正的业务请求,你看到跨域被浏览器阻止的时候,服务端根本就没有接受到业务请求,不存在服务端浪费资源执行业务逻辑的情况
    rf99wSiT6IxH1Z23
        8
    rf99wSiT6IxH1Z23  
       2020-09-02 18:42:31 +08:00
    @lalalaqwer 楼上解释不错
    mitu9527
        9
    mitu9527  
    OP
       2020-09-02 18:44:45 +08:00
    @lalalaqwer 那你的 OPTIONS 预检请求写在哪里?不都是 ajax 发送的地址么,预检请求后面没有业务逻辑代码么?你要是不去主动结束,不就会执行了么?
    asiufasd
        10
    asiufasd  
       2020-09-02 18:48:35 +08:00
    @mitu9527 本意是想让您自己再看一遍的,回答了那些问题我觉得就可以回答您的问题了。
    我帮您整理好您看一下。
    以下引用自您发出来的文章,
    1. “如果 Origin 指定的源,不在许可范围内,服务器会返回一个正常的 HTTP 回应。浏览器发现,这个回应的头信息没有包含 Access-Control-Allow-Origin 字段(详见下文),就知道出错了,从而抛出一个错误”,“如果服务器否定了"预检"请求,会返回一个正常的 HTTP 回应,但是没有任何 CORS 相关的头信息字段。这时,浏览器就会认定,服务器不同意预检请求,因此触发一个错误”;
    所以无论是简单请求还是非简单请求,跨域检测失败的响应头里都不会包含 CORS 相关的头信息字段,所以让客户端拒绝服务端,不需要特别返回响应头。
    2. “非简单请求的 CORS 请求,会在正式通信之前,增加一次 HTTP 查询请求,称为"预检"请求( preflight )。
    浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些 HTTP 动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的 XMLHttpRequest 请求,否则就报错。”,预检的响应头会包含你最开始列出的一些 Access-Control-*头(如果后端允许请求的话);
    这个请求是 options 请求,预检请求,并不会执行具体的逻辑,只有后端预检通过后,客户端才会发出正式的 XMLHttpRequest 请求。不存在"所有的逻辑都执行完了,然后你再加几个头部去告诉客户端把自己拒绝掉 "的问题、
    mitu9527
        11
    mitu9527  
    OP
       2020-09-02 18:49:39 +08:00
    @asiufasd @lalalaqwer @cnscorpions 我不知道你们是不是 PHP 开发人员,如果是的话,你们把我代码里面的两个 exit; 语句去掉,看看会怎么样。
    mitu9527
        12
    mitu9527  
    OP
       2020-09-02 18:53:58 +08:00
    @asiufasd 我已经说了,我看明白了,你回复的内容我都看了,而且我都明白,但是我感觉你并不清楚我在说什么。就问你一个问题吧,预检请求处理和简单请求处理,不都是在某个业务逻辑代码的前面写的么,如果程序不去 exit,会执行不到业务逻辑代码?
    111111111111
        13
    111111111111  
       2020-09-02 18:55:36 +08:00
    @mitu9527 把 exit 去掉,就算导致业务代码执行,和 php 没关系,也和 CORS 没关系,是你代码风格的问题,完全可以把业务代码写到 if 里面
    asiufasd
        14
    asiufasd  
       2020-09-02 18:57:14 +08:00
    @mitu9527 不要用自己错误的代码去证明跨域方案有问题
    mogita
        15
    mogita  
       2020-09-02 18:58:40 +08:00
    服务端的正确实现:OPTIONS 方法进来的请求不调用业务 handler,因此 preflight 请求不可能调用任何业务资源。
    mitu9527
        16
    mitu9527  
    OP
       2020-09-02 18:59:45 +08:00
    @111111111111 我没说和 PHP 有啥关系,我是在说,CORS 处理已经完成了,如果都已经知道拒绝了,何必再去执行剩余的代码,网上那种只加 header 的,你敢说没执行后面的代码?你说加 if,这个 if 该执行么?
    anUglyDog
        17
    anUglyDog  
       2020-09-02 19:00:48 +08:00   1
    @mitu9527
    1. 同源策略就是让开发者受限于浏览器安全约束,如果抛开 web 端,其实随便来个能发请求的终端都可以模拟浏览器,那你在跨域时不做服务端处理还有什么意义吗?
    2. 跨域不成功意味着用户根本用不到这段代码,因为开发者没做完这个产品,所以不能到用户手上。
    3. options 预检请求不通过,浏览器就不会发送 cookie,服务器验证不了用户,那还处理啥?
    also24
        18
    also24  
       2020-09-02 19:03:57 +08:00   3
    尝试着帮楼主解释一下。

    首先是大前提,楼主的思考方向,是在 『无框架协助』情况下,处理后端请求。
    划重点:无框架

    第 1 条,关于 OPTIONS 请求的处理:
    由于无框架,所以不管你的请求 method 是 GET POST 还是 OPTIONS,都会进入整个请求处理逻辑。
    自然的,OPTIONS 请求也直接进来了,如果你不将它单独处理,那确实可能造成问题。

    第 2 条,关于浏览器对跨域请求的拦截:
    @lalalaqwer #7 你的理解是有一定问题的,浏览器对于跨域请求,未必是在『发送请求』阶段拦截。
    你可以找个 Chrome 浏览器测试一下,Chrome 只是拦截了返回内容,服务器上你是可以收到这条请求的。


    由于以上两条,在『无框架』的场景下,确实有可能出现后端对跨域请求处理不合理,导致浏览器的 CORS 机制没有正确生效的情况。


    但是为什么很多人都不认可楼主的结论呢?
    第 1 条是因为『无框架』的场景实在是太少啦,现在基本上大事小事都会起框架,而框架往往都会对 OPTIONS 请求做自动处理。
    第 2 条,则真的是很多人没有注意过,因为各类文档上往往只会提到 『浏览器拦截跨域请求』,却没有详细的说明是在哪一个阶段拦截的。
    mitu9527
        19
    mitu9527  
    OP
       2020-09-02 19:03:57 +08:00
    @ck65 OPTIONS 请求默认情况下就是发到目标地址,我知道当然可以放在一个专用的页面处理,但那是另一说。那简单请求呢?如果 Origin 是跨源的,服务端不该 exit 一下么?
    Jirajine
        20
    Jirajine  
       2020-09-02 19:04:12 +08:00 via Android
    这是你代码的问题,没检验请求方法就执行业务逻辑。
    一般来说 web 框架就把这些处理了,option 请求根据路由根本匹配不到对应的 handler,自然也就不会触发业务逻辑。
    Kr98
        21
    Kr98  
       2020-09-02 19:06:07 +08:00
    其实楼主想说的等于是实现一个 cors middleware 吧,但这个本来就是服务端正常的处理模式。
    可以交给 nginx,也可以交给 middleware,一般不需要自己再加什么东西。
    mitu9527
        22
    mitu9527  
    OP
       2020-09-02 19:07:42 +08:00
    @Jirajine 我都没说框架,你非要说框架把这个处理了,对不上啊。代码都贴出来了,代码有啥问题你说说吧。
    VeryZero
        23
    VeryZero  
       2020-09-02 19:09:18 +08:00
    同源策略是浏览器做的,所以服务端如何知道自己的返回会被浏览器拦截。如果请求方使用代理中转不走浏览器呢?
    ChanKc
        24
    ChanKc  
       2020-09-02 19:15:45 +08:00   1
    我觉得楼主说的是对的
    我猜楼主的意思是:如果没有 preflight,不合要求的 CORS 请求应该直接拒绝,不需要执行正常的后端逻辑
    首先 preflight 不是必须的,比如说有 preflight cache 的情况下是不会发 preflight 的
    但其实更简单些,校验 Origin,不合要求 4xx 完事。这样甚至无所谓客户端到底是不是浏览器了
    VeryZero
        25
    VeryZero  
       2020-09-02 19:16:26 +08:00
    另外,如果你觉得被拦截下来的响应浪费资源可以自己处理,比如像你代码里的那样。

    但是你不觉得这样更加多此一举么?谁会一直请求一个不允许跨域 URL ?

    跳过一个偶尔跨域失败的响应真的能省资源吗?如果省资源的意义都没有了,你做特殊处理的意义又在哪
    mogita
        26
    mogita  
       2020-09-02 19:22:41 +08:00
    @mitu9527 应该 exit 就 exit 啊,和自己较什么劲。CORS 就是一纸规范,实现跟着规范走就完了又没人不准你 exit 。
    mitu9527
        27
    mitu9527  
    OP
       2020-09-02 19:28:05 +08:00
    @VeryZero 我在讨论的是不应该去做,你却再说做了应该也没啥影响,这样好么?后续的业务逻辑各种各样,你怎么能确定执行了不会有问题?既然服务端自己都能判断出前端请求是跨域的,就算业务代码执行完成了也会被前端拒绝,那何必还去执行呢?
    VeryZero
        28
    VeryZero  
       2020-09-02 19:29:54 +08:00
    其实个人觉得预检请求出现的目的之一就是解决题主类似的问题的。

    先预检下是否支持跨域,防止在不允许跨域的情况下执行了不应该执行的逻辑,修改了不该修改的数据。
    workwonder
        29
    workwonder  
       2020-09-02 19:36:11 +08:00 via Android
    个人觉得因为 cors 是可选的,让浏览器做一个保证就满足要求了。又由于 cors 是可以关闭的,加上不是所有请求都是来自浏览器环境的,所以服务器端强制执行 cors 的意义被削弱了。
    一般 options 请求没有业务逻辑,而 get 请求没有副作用。针对 get 请求确实可以提前识别出 cors 不满足而提前结束响应,只是可能标准没有强制,正好主流实践也没有关注而已吧。
    Lax
        30
    Lax  
       2020-09-02 19:38:44 +08:00
    ajax 运行之前的 OPTIONS 请求是由浏览器发起的,不是 js 代码发起。上面 @lalalaqwer 回答解释的已经比较清楚了。

    在服务器一端来看,OPTIONS /path/to/api 和 GET/POST /path/to/api 是两种不同的请求 [区别也很明显:如果客户端代码发起 post 请求,OPTIONS 请求里不包含请求体,更不要提后面逻辑去处理了] ,本来就应该去做不同的处理。

    类似的情况还有 HEAD,服务器端也不能无脑走 GET 的逻辑。
    Torpedo
        31
    Torpedo  
       2020-09-02 19:41:44 +08:00   1
    楼主思路就是对的。如果只对浏览器,我记我们后端 java 用的库就是,如果不符合 cors 。就会停止后面的逻辑,返回报错
    VeryZero
        32
    VeryZero  
       2020-09-02 20:01:42 +08:00
    @Torpedo 刚去试了下 Spring,确实是这样的。直接返回了,不执行后面的逻辑。
    no1xsyzy
        33
    no1xsyzy  
       2020-09-02 20:04:00 +08:00   1
    @mitu9527 #22 @Jirajine 说的框架是指:
    上面回复的不少人通常都把 OPTIONS 的问题交给框架了,所以没发生你的问题。

    OPTIONS 不应该执行业务逻辑,就好像 GET 你不会突然决定删库。
    浏览器完全可能给你发一万个 OPTIONS 而一个业务逻辑相关内容都不发。



    另外,其实你现在的这段代码就算加了两个 exit; 仍然是有问题的。给你来点恶意负载:

    OPTIONS /api HTTP/1.1
    Host: example.com

    你仍然会执行业务逻辑。
    mitu9527
        34
    mitu9527  
    OP
       2020-09-02 20:10:51 +08:00
    @no1xsyzy 就算不说 OPTIONS,只谈简单请求,不也一样么,如果服务端根据自己的配置已经识别出浏览器发上来的请求是跨域的请求,直接 exit,既不会执行后续代码,浏览器也收不到 Access-Control-*,不挺好么。

    这段代码没打算投入使用,就是做演示用的。我也知道框架或 web 服务器可以帮我们做处理,但是觉得讨论问题时把它们拉进来不是更复杂了么。
    lalalaqwer
        35
    lalalaqwer  
       2020-09-02 20:15:12 +08:00 via Android
    @also24 这里我的确是没有考虑简单请求的情况
    JimmyChange
        36
    JimmyChange  
       2020-09-02 20:21:05 +08:00
    感觉楼主就是想要不向按照标准要求的正常逻辑处理,标准说跨域 Prelight 请求应该返回特定头部字段,楼主说返回啥啊,都知道是非法请求了,还返回啥啊,直接退出函数不就得了

    这种思路怎么说,自己公司内部玩可以,但是云服务那种,如果第三方对接,啥头部都不返回,怕不是要被第三方烦死。。。
    mitu9527
        37
    mitu9527  
    OP
       2020-09-02 20:27:14 +08:00
    @JimmyChange 我确实没看过标准,我是参照阮一峰的那篇文章写的,另外我觉得那篇文章中的逻辑也没问题。客户端发请求上来问服务端跨没跨域,服务端如果发现请求没跨域,自然要告诉客户端自己允许什么,如果服务端发现请求是跨域了,都是不是自己的客户,干嘛要告诉客户端自己的规则是什么,直接返回,相当于不理客户端,不是挺合理的么?
    also24
        38
    also24  
       2020-09-02 20:28:07 +08:00
    @lalalaqwer #35
    是的,我的措辞也需要补充,应该分为 『简单请求』和 『需预检请求』来讨论。

    https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
    JimmyChange
        39
    JimmyChange  
       2020-09-02 20:36:31 +08:00 via iPhone
    @mitu9527 所以我说嘛,公司自己的业务你咋写都行,标准里提出这玩意儿,为了保证向后兼容老系统和浏览器,肯定是你怎么做都有正确结果,但你要是考虑内部系统测试、对接第三方,不返回就会神烦
    no1xsyzy
        40
    no1xsyzy  
       2020-09-02 20:49:45 +08:00
    @mitu9527 PHP exit 是相当于 deny 么?这我倒是不知道…… 不过有效的关于错误的应答,我能想到如下几个原因:
    1. 适应自动重发,不告知 Origin 有问题的话,可能会不断自动重发导致 DDOS ;
    2. 考虑 OPTIONS 被缓存的可能性;
    3. Service Worker 没有 deny 的选项(不清楚跨域是否会调用 Service Worker );
    4. 没有任何错误的话,排障就麻烦了,域名 typo 查了一下午(
    ChanKc
        41
    ChanKc  
       2020-09-02 20:52:27 +08:00
    阮一峰就很多地方说不通
    我前几天面试也被问简单请求,当时因为是远程的,顺手打开 spec,一搜 simple 啥都没有,直接就说我不会
    如果要按是否 preflight 来分,spec 说

    A request has an associated use-CORS-preflight flag. Unless stated otherwise, it is unset.

    The use-CORS-preflight flag being set is one of several conditions that results in a CORS-preflight request. The use-CORS-preflight flag is set if either one or more event listeners are registered on an XMLHttpRequestUpload object or if a ReadableStream object is used in a request.

    If the CORS-preflight flag is set and one of these conditions is true:

    There is no method cache entry match for request’s method using request, and either request’s method is not a CORS-safelisted method or request’s use-CORS-preflight flag is set.

    There is at least one item in the CORS-unsafe request-header names with request’s header list for which there is no header-name cache entry match using request.

    所以除了那些请求头和请求方法以外要考虑的还有是否有缓存(很重要)。另外有 preflight 了不代表普通的 CORS 请求不需要校验,不需要那几个头,只要是 HTTP fetch,都要执行下面两步



    Set response and actualResponse to the result of performing an HTTP-network-or-cache fetch using request.

    If request’s response tainting is "cors" and a CORS check for request and response returns failure, then return a network error.

    response tainting 是 cors 的都要去检查 HTTP 头

    至于什么“兼容表单”也是有点问题。表单提交的请求模式是 navigate,对应的 response tainting 是 basic,所以根本不做 CORS check,自然也就用不上 preflight
    mitu9527
        42
    mitu9527  
    OP
       2020-09-02 21:10:49 +08:00
    @no1xsyzy @ChanKc 可能我在内容里面说的“完善”确离“完善”还差很远,不过我的本意也不是想说的代码写的多好,多完善,我是想说的重点是提前 exit 不去执行下面的业务逻辑。回头我去看下规范或者看看别的库和框架是怎么实现的吧。
    baobao1270
        43
    baobao1270  
       2020-09-02 22:05:02 +08:00
    额,CROS 的本质是浏览器防止 XSS 对客户端攻击的,我个人认为服务器只要支持好预检请求即可。服务端应另行对客户端请求合法性进行校验,因为一个不进行 CROS 检查的客户端可以直接构造请求。
    no1xsyzy
        44
    no1xsyzy  
       2020-09-03 11:03:16 +08:00
    @ChanKc ……简单请求不是 CORS 标准的用词,而是 MDN 描述 “不需要预检” 的情况的用词。同时,“这些跨域请求与浏览器发出的其他跨域请求并无二致。”
    至于兼容表单…… 按照 fetch standard,原句表示的不是简单请求 “兼容表单”,而是指 “任何比 <form> 侵入性更强的操作均需要预检请求”
    For requests that are more involved than what is possible with HTML’s form element, a CORS-preflight request is performed, to ensure request’s current URL supports the CORS protocol.
    应当说表单是一个朴素的侵入程度分界线。
    no1xsyzy
        45
    no1xsyzy  
       2020-09-03 11:12:21 +08:00
    @mitu9527 因为框架导致忽略了这一个问题吧
    比如 flask-cors 可以进行全局覆盖,无视 path,任何 OPTIONS 均作同一处理。
    一些 nginx 实现方式也是类似的。
    那连上面这么多 is... check... addHeader... 都是不需要的了,直接开始写业务代码就成。
    ChanKc
        46
    ChanKc  
       2020-09-03 11:32:02 +08:00
    @no1xsyzy 所以我说阮的表述是有些误导性的
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2554 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 15:05 PVG 23:05 LAX 07:05 JFK 10:05
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86