能否跨域使用XMLHttpRequest?

10

JavaScript能够进行跨站点XMLHttpRequest吗?

我知道这有限制并且通常不能工作,但自Firefox 3.5以来,有了

Access-Control-Allow-Origin: *

它应该允许此操作。

它告诉浏览器,服务器不关心请求是否来自未提供页面的域。

下面是我使用的代码。

function sendData(webservicePayload, callbackFunction) {
var request = null;
if (!window.XMLHttpRequest) { // code for IE
    try {
        request = new ActiveXObject('Msxml2.XMLHTTP');
    } catch (e) {
        try {
            request = new ActiveXObject('Microsoft.XMLHTTP');
        } catch (E) {
            return 'Create XMLHTTP request IE';
        }
    }
} else { // code for Mozilla, etc.
    request = new XMLHttpRequest();
}
/*
 * Setup the callback function
 */
request.onreadystatechange = function() {
    if (request.readyState == 4 && request.status < 300) {
        eval(callbackFunction);
    }
};
if (!request) {
    nlapiLogExecution('ERROR', 'Create XMLHTTP request', 'Failed');
    return;
}
/*
 * Setup the request headers
 */

request.open('POST','http://www.another.domain.co.uk/webservice.asmx', true);
request.setRequestHeader('Man','POST http://www.another.domain.co.uk/webservice.asmx HTTP/1.1');
request.setRequestHeader('MessageType', 'CALL');
request.setRequestHeader('Content-Type', 'text/xml; charset="utf-8"');
request.setRequestHeader('Cache-Control', 'no-cache');
request.setRequestHeader("X-Requested-With", "XMLHttpRequest");
request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

request.setRequestHeader('SOAPAction','http://www.another.domain.co.uk/WebService/eService');
request.send(webservicePayload);

这将发送正确的请求头

请求

OPTIONS /webservice.asmx HTTP/1.1
Host: www.another.domain.co.uk
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:8.0) Gecko/20100101 Firefox/8.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-gb,en;q=0.5
Accept-Encoding: gzip, deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Origin: https://my.domain.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: cache-control,content-type,man,messagetype,soapaction
Pragma: no-cache
Cache-Control: no-cache

并且接收到一个预期的响应头。

响应

HTTP/1.1 403 Forbidden
Server: Microsoft-IIS/5.1
Date: Wed, 14 Dec 2011 13:43:27 GMT
X-Powered-By: ASP.NET
Access-Control-Allow-Origin: *
Connection: close
Content-Type: text/html
Content-Length: 44

正如您所看到的,"Origin" 在请求中被指定,服务器响应接受任何("*")域。

为什么我会收到"禁止访问 403" 的消息?我感觉我做的一切都是正确的,但我无法弄清楚原因。

是否还有其他人遇到这个问题?

您知道是什么原因导致的吗?


2
浏览器,不是所有的浏览器都支持CORS。 - Raynos
对于IE浏览器,您需要使用XDomainRequest而不是XMLHTTPRequest。但是,跨域XHR非常有效,例如我使用它从我的网站向imgur发送数据。我建议使用库来抽象掉糟糕的细节。 - Matt Greer
似乎更像是服务器问题而不是JS/浏览器问题。检查一下你的APS代码,确保正确处理OPTIONS请求。 - Gerben
正如您从标题中所看到的,我正在使用Firefox 8.0 用户代理:Mozilla/5.0(Windows NT 6.1; rv:8.0)Gecko/20100101 Firefox/8.0 这个解决方案应该是通用的,所以我将为IE8更改XDomainRequest的代码。 - Javanerd
1个回答

4
一个 CORS 请求实际上包含两个物理 HTTP 请求:1)预检请求,和 2)实际请求。你上面发布的请求看起来像是预检请求,因为它使用了 HTTP OPTIONS 方法。所以你需要做的第一件事就是验证你的服务器是否接受 OPTIONS 请求(我相信这应该可以正常工作,但这可能解释了为什么你收到了 403 错误)。
接下来,你需要一个有效的预检响应。对于预检请求的响应还必须包含以下两个标头:
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Origin,cache-control,content-type,man,messagetype,soapaction

请看这些响应头是如何回应Access-Control-Request-Method和Access-Control-Request-Headers请求头的。Access-Control-Allow-Headers头应该包含任何自定义请求头。

一旦浏览器接收到此响应,它就知道预检请求已被接受,并进行实际请求。在实际请求中,您只需要以下标头:

Access-Control-Allow-Origin: *

您可以在这里了解有关预检请求和处理CORS请求的更多信息:http://www.html5rocks.com/en/tutorials/cors/

我一定会试一试。这个方案应该是可行的,而且回复也非常详细。非常感谢。 - Javanerd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接