【问题标题】:CORS request is preflighted, but it seems like it should not beCORS 请求已预检,但似乎不应该
【发布时间】:2013-06-08 01:57:33
【问题描述】:

以下跨域 POST 请求,内容类型为 multipart/form-data 且仅预检了简单的标头。根据 W3C 规范,除非我读错了,否则不应预检。我已经确认这发生在 Chrome 27 和 Firefox 10.8.3 中。我没有测试任何其他浏览器。

这里是请求标头等:

Request URL:http://192.168.130.135:8081/upload/receiver
Request Method:POST
Status Code:200 OK
Request Headersview source
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Content-Length:27129
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryix5VzTyVtCMwcNv6
Host:192.168.130.135:8081
Origin:http://192.168.130.135:8080
Referer:http://192.168.130.135:8080/test/raytest-jquery.html
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.37 Safari/537.36

这是 OPTIONS(预检)请求:

Request URL:http://192.168.130.135:8081/upload/receiver
Request Method:OPTIONS
Status Code:200 OK
Request Headersview source
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:origin, content-type
Access-Control-Request-Method:POST
Connection:keep-alive
Host:192.168.130.135:8081
Origin:http://192.168.130.135:8080
Referer:http://192.168.130.135:8080/test/raytest-jquery.html
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.37 Safari/537.36

规范似乎很清楚:

更新:这里有一些简单的客户端代码可以重现这个:

var xhr = new XMLHttpRequest(),
    formData = new FormData();

formData.append('myfile', someFileObj);

xhr.upload.progress = function(e) {
    //insert upload progress logic here
};

xhr.open('POST', 'http://192.168.130.135:8080/upload/receiver', true);
xhr.send(formData);

有人知道为什么要预检吗?

【问题讨论】:

    标签: xmlhttprequest cors multipartform-data xmlhttprequest-level2


    【解决方案1】:

    我最终检查了 Webkit 源代码以试图弄清楚这一点(在 Google 没有产生任何有用的点击之后)。事实证明,只要您注册一个onprogress 事件处理程序,Webkit 就会强制预检任何跨域请求。即使在阅读了代码 cmets 之后,我也不完全确定为什么要应用这种逻辑。

    在 XMLHttpRequest.cpp 中:

    void XMLHttpRequest::createRequest(ExceptionCode& ec)
    {
        ...
    
        options.preflightPolicy = uploadEvents ? ForcePreflight : ConsiderPreflight;
    
        ...
    
        // The presence of upload event listeners forces us to use preflighting because POSTing to an URL that does not
        // permit cross origin requests should look exactly like POSTing to an URL that does not respond at all.
        // Also, only async requests support upload progress events.
        bool uploadEvents = false;
        if (m_async) {
            m_progressEventThrottle.dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadstartEvent));
            if (m_requestEntityBody && m_upload) {
                uploadEvents = m_upload->hasEventListeners();
                m_upload->dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadstartEvent));
            }
        }
    
        ...
    }
    


    更新: Firefox 应用与 Webkit 相同的逻辑,看起来。以下是来自 nsXMLHttpRequest.cpp 的相关代码:

    nsresult
    nsXMLHttpRequest::CheckChannelForCrossSiteRequest(nsIChannel* aChannel)
    {
        ...
    
        // Check if we need to do a preflight request.
        nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
        NS_ENSURE_TRUE(httpChannel, NS_ERROR_DOM_BAD_URI);
    
        nsAutoCString method;
        httpChannel->GetRequestMethod(method);
        if (!mCORSUnsafeHeaders.IsEmpty() ||
            (mUpload && mUpload->HasListeners()) ||
            (!method.LowerCaseEqualsLiteral("get") &&
             !method.LowerCaseEqualsLiteral("post") &&
             !method.LowerCaseEqualsLiteral("head"))) {
          mState |= XML_HTTP_REQUEST_NEED_AC_PREFLIGHT;
        }
    
        ...
    }
    

    注意条件的mUpload &amp;&amp; mUpload-&gt;HasListeners() 部分。

    似乎 Webkit 和 Firefox(可能还有其他)在他们的预检代码中插入了一些未被 W3C 规范认可的逻辑。如果我在规范中遗漏了什么,请发表评论。

    【讨论】:

    • 这是一个了不起的发现!客户端代码触发预检很奇怪;规范中对此没有任何内容。此外,评论并没有使事情更清楚。我建议在 WebKit 板上提出这一点以进行澄清。
    • @monsur 我怀疑这种逻辑不仅限于 Webkit。我在使用 Firefox 时也遇到了同样的问题。我还没有测试过IE10。我也打算看看 Firefox 的源代码,看看能否证实我的怀疑。
    • 我已经提交了一个 Webkit 错误,尽管这个逻辑也出现在 Firefox 和 IE10 中。 bugs.webkit.org/show_bug.cgi?id=117577
    • 所以听起来这不是一个错误。在 XHR 规范中搜索单词“preflight”的第二个实例:w3.org/TR/XMLHttpRequest 这表明上传事件会强制进行预检,因为上传事件会引入在 CORS 之前不可用的新信息。然而,令人困惑的是,CORS 规范中没有包含这一点。
    • 很高兴找到这个。感觉就像一个量子错误:CORS 错误仅在我有一个上传事件侦听器时发生(如果响应是重定向,则预检 CORS 错误)
    【解决方案2】:

    我的猜测是Content-Type 标头上的“边界”会导致问题。如果您能够重现此问题,则应将其作为浏览器错误提交,因为规范规定 Content-Type 标头检查应排除参数。

    【讨论】:

    • 那是我最初的怀疑,但它比那更险恶。我刚刚检查了 Webkit 源代码,并弄清楚了为什么会发生这种情况。我会将我的答案发布为社区 wiki。
    猜你喜欢
    • 2019-10-13
    • 2013-12-24
    • 2013-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-29
    • 2021-02-18
    • 2021-03-27
    相关资源
    最近更新 更多