CORS请求是prelighted,但它似乎不应该是 [英] CORS request is preflighted, but it seems like it should not be

查看:182
本文介绍了CORS请求是prelighted,但它似乎不应该是的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面的跨源POST请求,带有multipart / form-data的内容类型,并且只有简单的报头。根据W3C规范,除非我读错了,它不应该被预检。我确认这发生在Chrome 27和Firefox 10.8.3。



以下是请求标头等:

 请求URL:http://192.168.130.135:8081 / upload / receiver 
请求方法:POST
状态码:200 OK
请求Headersview源
接受:* / *
接受编码:gzip,deflate,sdch
接受语言:en-US,en; q = 0.8
连接:keep-alive
Content-长度:27129
Content-Type:multipart / form-data; boundary = ---- WebKitFormBoundaryix5VzTyVtCMwcNv6
Host:192.168.130.135:8081
原产地:http://192.168.130.135:8080
参考者: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,如Gecko)Chrome / 28.0.1500.37 Safari / 537.36



这里是OPTIONS(预检)请求:

 请求URL:http://192.168.130.135:8081 / upload / receiver 
请求方法:选项
状态代码:200 OK
请求Headersview源
接受:* / *
接受编码:gzip,deflate,sdch
Accept-Language:en-US,en; q = 0.8
访问控制请求标头: -type
Access-Control-Request-Method:POST
连接:keep-alive
主机:192.168.130.135:8081
原产地: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 Gecko)Chrome / 28.0.1500.37 Safari / 537.36

这个规格看起来很清楚:





UPDATE:以下是一些简单的客户端代码:

  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);

有没有人知道为什么会被预检?

解决方案

我最后检查了Webkit源代码试图找出这一点(在谷歌没有产生任何有用的命中)。事实证明,如果您注册一个 onprogress 事件处理程序,Webkit将强制任何跨源请求被简单地预检。我不完全确定,即使在阅读代码注释后,为什么应用这个逻辑。



在XMLHttpRequest.cpp中:

  void XMLHttpRequest :: createRequest(ExceptionCode& ec)
{
...

options.preflightPolicy = uploadEvents? ForcePreflight:

...

//上传事件监听器的存在迫使我们使用预检,因为发送到不是
的URL允许跨源请求应该看起来完全像POST到一个不响应的URL。
//此外,只有异步请求支持上传进度事件。
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)
{
...

//检查我们是否需要执行预检请求。
nsCOMPtr< nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
NS_ENSURE_TRUE(httpChannel,NS_ERROR_DOM_BAD_URI);

nsAutoCString方法;
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&& mUpload-> HasListeners()部分条件。



似乎Webkit和Firefox预检确定代码,未经W3C规范批准。如果我缺少某些规格,请评论。


The following cross-origin POST request, with a content-type of multipart/form-data and only simple headers is preflighted. According to the W3C spec, unless I am reading it wrong, it should not be preflighted. I've confirmed this happens in Chrome 27 and Firefox 10.8.3. I haven't tested any other browsers.

Here are the request headers, etc:

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

And here is the OPTIONS (preflight) request:

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

The spec seems pretty clear:

UPDATE: Here's some simple client-side code that will reproduce this:

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);

Does anyone know why this is being preflighted?

解决方案

I ended up checking out the Webkit source code in an attempt to figure this out (after Google did not yield any helpful hits). It turns out that Webkit will force any cross-origin request to be preflighted simply if you register an onprogress event handler. I'm not entirely sure, even after reading the code comments, why this logic was applied.

In 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));
        }
    }

    ...
}


UPDATE: Firefox applies the same logic as Webkit, it appears. Here is the relevant code from 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;
    }

    ...
}

Notice the mUpload && mUpload->HasListeners() portion of the conditional.

Seems like Webkit and Firefox (and possibly others) have inserted some logic into their preflight-determination code that is not sanctioned by the W3C spec. If I'm missing something in the spec, please comment.

这篇关于CORS请求是prelighted,但它似乎不应该是的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆