首页 > 解决方案 > 在使用 CORS 的情况下,Edge 浏览器不会重定向呼叫

问题描述

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

我发现在 GET 和 POST 请求的 HTTP 302 Found 响应的情况下,Edge 浏览器不遵循 Location 标头。

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


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

  2. 使用自定义标头集对https://some-service.io/login进行异步 GET 调用

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

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

由于 CORS 启用了 withCredentials,数据属性有一个空对象(用于 axios 调用)或一些虚拟数据(用于 javascript 调用),因为我们在 Chrome/FF 中遇到了重定向调用标头的问题:

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 和 Location: https://some-service.io/login/auth标头,我们需要将原始标头和通过重定向调用设置的 cookie 发送到 https:// some-service.io/login/auth
  2. 对于对https://some-service.io/login/auth的重定向调用,服务器响应 HTTP 200,如果在请求标头中设置了 Content-Type,则返回 json-object:

    • Chrome/FF 完美运行,遵循重定向,初始调用的标头也可用于重定向调用,HTTP 200 返回有效的 json-object
    • 边缘浏览器根本不遵循 Location 标头值
    • IE 11 浏览器遵循 Location 标头中的重定向 url,但在初始调用中没有设置标头(添加仅用于比较)

原始 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 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,缺失)

铬合金

-- 选项(预检)

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

标签: javascriptcorsaxiosmicrosoft-edge

解决方案


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


推荐阅读