在使用 CORS 的情况下,Edge 浏览器不会重定向调用

Edge browser doesn't redirect the call in case of CORS used

请帮我找到适合 Edge 浏览器的解决方案。

我发现 Edge 浏览器在 GET 和 POST 请求的 HTTP 302 Found 响应的情况下不遵循位置 header。

简而言之,相同的代码(见下面的解释):


  1. 打开的页面:https://example.com

  2. https://some-service.io/login 进行异步 GET 调用,自定义 headers 设置

    Content-Type = application/json; charset=utf-8 
    X-Header = http://some-service.io/xxx-yyy-zzz

注意:页面和服务使用不同的域

并且由于 CORS 启用了 withCredentials,数据属性有一个空的 object(对于 axios 调用)或一些虚拟数据(对于 javascript 调用),因为我们在 [=135 中遇到了问题=] 与 headers 用于重定向调用:

Javascript版本

function httpGetAsync(url, method, callback) {
    var xmlHttp = new XMLHttpRequest();

    xmlHttp.onreadystatechange = function ()
    {
        if (xmlHttp.readyState == XMLHttpRequest.DONE && xmlHttp.status == 200) {
            console.log('DONE');
            callback(xmlHttp.readyState + ':' + xmlHttp.status + ':' + xmlHttp.response);
            return;
        }

        console.log(xmlHttp.readyState + ':' + xmlHttp.status + ':' + xmlHttp.response);
        var headers = xmlHttp.getAllResponseHeaders();
        console.log('headers: ' + headers.toString());
    }

    xmlHttp.open(method, url, true); // true for asynchronous
    xmlHttp.withCredentials = true;
    xmlHttp.setRequestHeader('Accept', 'application/json');
    xmlHttp.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
    xmlHttp.setRequestHeader('X-Header', 'https://some-service.io/xxx-yyy-zzz');
    xmlHttp.send("foo=bar&lorem=ipsum");
}

httpGetAsync('https://some-service.io/login', 'GET', function (response) {
    console.log(response);
});

AXIOS版本

        ...
        defaultHeaders['Content-Type'] = 'application/json;charset=UTF-8';
        defaultHeaders['X-Header'] = 'https://some-service.io/xxx-yyy-zzz';
        ...
        axios({
            method: 'GET',
            url: 'https://some-service.io/login',
            withCredentials: true,
            headers: defaultHeaders,
            data: {}
        }).then(response => {
        ...
  1. 服务器以 HTTP 302 响应,Set-Cookie 和位置:https://some-service.io/login/auth headers in the response, we need to send original headers and the cookies set with the redirected call to https://some-service.io/login/auth
  2. 对于重定向到 https://some-service.io/login/auth 的调用,服务器以 HTTP 200 响应, json-object 如果在请求中设置 Content-Type 则返回 headers:

    • Chrome/FF 完美运行,遵循重定向,初始调用的 headers 也可用于重定向调用,HTTP 200 返回有效 json-object
    • Edge 浏览器根本不遵循位置 header 值
    • IE 11 浏览器遵循来自位置 header 的重定向 url,但在初始调用中没有设置 Headers(添加只是为了比较)

RAW HTTP

边缘

-- 选项(预检)

OPTIONS https://some-service.io/login HTTP/1.1
Origin: https://example.com
Referer: https://example.com?uuid=38db98a3-f6f0-11e9-b2be-6814011b702b
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18362
Access-Control-Request-Headers: content-type,database,dictionarydomain,language,site,x-referer-epay
Access-Control-Request-Method: GET
Accept: */*
Accept-Language: en-US,en;q=0.8,cs;q=0.6,ru;q=0.4,uk;q=0.2
Accept-Encoding: gzip, deflate, br
Host: some-service.io
Content-Length: 0
DNT: 1
Connection: Keep-Alive
Cache-Control: no-cache

-- GET 请求

GET https://some-service.io/login HTTP/1.1
Origin: https://example.com
Referer: https://example.com?uuid=38db98a3-f6f0-11e9-b2be-6814011b702b
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18362
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.8,cs;q=0.6,ru;q=0.4,uk;q=0.2
Content-Type: application/json;charset=UTF-8
X-Header: https://some-service.io/xxx-yyy-zzz
Accept-Encoding: gzip, deflate, br
Host: some-service.io
DNT: 1
Connection: Keep-Alive

-- 获取响应

HTTP/1.1 302 Found
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://example.com
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Date: Tue, 10 Dec 2019 12:26:08 GMT
Expires: 0
Location: https://some-service.io/login/auth
Pragma: no-cache
Set-Cookie: JSESSIONID=CC10DD73C968C42C5A007D27342BF0B5; Path=/; Secure
Set-Cookie: __VCAP_ID__=32ee654d-2947-49e4-4909-9bc7; Path=/; HttpOnly; Secure
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-Vcap-Request-Id: ef27c9ae-fa5b-45b6-5c6a-9537b159e533
X-Xss-Protection: 1; mode=block
Content-Length: 0
Connection: keep-alive

-- 重定向调用的 GET 请求(https://some-service.io/login/auth,缺失)

Chrome

-- 选项(预检)

OPTIONS https://some-service.io/login HTTP/1.1
Host: some-service.io
Connection: keep-alive
Access-Control-Request-Method: GET
Origin: https://example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36
Access-Control-Request-Headers: content-type,database,dictionarydomain,language,site,x-referer-epay
Accept: */*
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: cors
Referer: https://example.com?uuid=38db98a3-f6f0-11e9-b2be-6814011b702b
Accept-Encoding: gzip, deflate, br
Accept-Language: en,ru-RU;q=0.9,ru;q=0.8,en-US;q=0.7,en-GB;q=0.6

-- GET 请求

GET https://some-service.io/login HTTP/1.1
Host: some-service.io
Connection: keep-alive
Origin: https://example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36
Content-Type: application/json;charset=UTF-8
Accept: application/json, text/plain, */*
X-Header: https://some-service.io/xxx-yyy-zzz
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: cors
Referer: https://example.com?uuid=38db98a3-f6f0-11e9-b2be-6814011b702b
Accept-Encoding: gzip, deflate, br
Accept-Language: en,ru-RU;q=0.9,ru;q=0.8,en-US;q=0.7,en-GB;q=0.6
Cookie: JSESSIONID=998B805DAF1BBA4C76AB930702C49131; __VCAP_ID__=a3ed6e06-6e23-43ad-469a-e848

-- 获取响应

HTTP/1.1 302 Found
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://example.com
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Date: Tue, 10 Dec 2019 10:33:02 GMT
Expires: 0
Location: https://some-service.io/login/auth
Pragma: no-cache
Set-Cookie: __VCAP_ID__=32ee654d-2947-49e4-4909-9bc7; Path=/; HttpOnly
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-Vcap-Request-Id: e207bdaa-20a6-48a1-7f97-b0688d2f1f98
X-Xss-Protection: 1; mode=block
Content-Length: 0
Connection: keep-alive

-- GET请求重定向调用(https://some-service.io/login/auth)

GET https://some-service.io/login/auth HTTP/1.1
Host: some-service.io
Connection: keep-alive
Origin: https://example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36
Content-Type: application/json;charset=UTF-8
Accept: application/json, text/plain, */*
Database: master
X-Header: https://some-service.io/xxx-yyy-zzz
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: cors
Referer: https://example.com?uuid=38db98a3-f6f0-11e9-b2be-6814011b702b
Accept-Encoding: gzip, deflate, br
Accept-Language: en,ru-RU;q=0.9,ru;q=0.8,en-US;q=0.7,en-GB;q=0.6
Cookie: JSESSIONID=998B805DAF1BBA4C76AB930702C49131; __VCAP_ID__=32ee654d-2947-49e4-4909-9bc7

-- 获取响应

HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://example.com
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: application/json;charset=UTF-8
Date: Tue, 10 Dec 2019 10:35:35 GMT
Expires: 0
Pragma: no-cache
Set-Cookie: __VCAP_ID__=a3ed6e06-6e23-43ad-469a-e848; Path=/; HttpOnly
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-Vcap-Request-Id: ad084e82-1038-4953-5f40-cfcf4f4c10d3
X-Xss-Protection: 1; mode=block
Content-Length: 16
Connection: keep-alive

{"some-value":0}

备注

    Sec-Fetch-Site: cross-site
    Sec-Fetch-Mode: cors

为了缓解不同浏览器的 CORS 实现差异,我决定将 CORS 请求从 FE 端移动到 BE 端。 已实现小型透明代理以服务从 FE 到 BE 的请求,并使用 RestClient(或 HttpClient)组件从 BE 调用服务,与从 FE 到服务的直接调用相比,它与 CORS 和重定向调用完美配合。