首页 > 解决方案 > CORS 在 Safari 中阻止一个 API 请求(而不是其他请求)

问题描述

我正在运行一个 React (16) webapp(部署在 Netlify 上),如果它的 API 调用被 CORS 阻止但仅在 Safari 中,它会失败。在 Chrome 或 Firefox 中没有问题。控制台显示以下内容:

Origin https://chicha.netlify.app is not allowed by Access-Control-Allow-Origin.
XMLHttpRequest cannot load https://chicha-api.herokuapp.com/votes due to access control checks.
Failed to load resource: Origin https://chicha.netlify.app is not allowed by Access-Control-Allow-Origin.

被阻止请求的标头(Safari):

Summary
URL: https://chicha-api.herokuapp.com/votes
Status: —
Source: —
Initiator: 
xhr.js:178


Request
Accept: application/json, text/plain, */*
Origin: https://chicha.netlify.app
Referer: https://chicha.netlify.app/events
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Safari/605.1.15
X-Requested-With: XMLHttpRequest

Response
No response headers

以下是未被阻止的同一请求的标头(Chrome):

Request URL: https://chicha-api.herokuapp.com/votes
Request Method: OPTIONS
Status Code: 204 No Content
Remote Address: 52.214.138.78:443
Referrer Policy: no-referrer-when-downgrade
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: x-requested-with
Access-Control-Allow-Methods: GET,HEAD,PUT,PATCH,POST,DELETE
Access-Control-Allow-Origin: https://chicha.netlify.app
Connection: keep-alive
Content-Length: 0
Date: Wed, 03 Jun 2020 10:43:59 GMT
Server: Cowboy
Vary: Origin, Access-Control-Request-Headers
Via: 1.1 vegur
X-Powered-By: Express
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en,es;q=0.9,ca;q=0.8,fr;q=0.7
Access-Control-Request-Headers: x-requested-with
Access-Control-Request-Method: GET
Connection: keep-alive
Host: chicha-api.herokuapp.com
Origin: https://chicha.netlify.app
Referer: https://chicha.netlify.app/events
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36

该应用程序使用配置如下的 axios 进行调用:

class ApiClient {
  constructor() {
    this.apiClient = axios.create({
      baseURL: process.env.REACT_APP_BACKEND_URI,
      withCredentials: true,
      headers: { 'X-Requested-With': 'XMLHttpRequest' },
    });
  }

  getVotes = () => this.apiClient.get('/votes');
  getEvents = () => this.apiClient.get('/events');
...

API(在 Heroku 上部署 Express 的 Node.js)具有以下 CORS 配置:

app.use(
    cors({
        credentials: true,
        origin: [process.env.FRONTEND_DOMAIN],
    })
);

... Heroku 上的环境配置变量在FRONTEND_DOMAIN哪里。https://chicha.netlify.app

奇怪的是其他 API 请求没有问题。成功请求的 API 标头 (Safari):

Summary
URL: https://chicha-api.herokuapp.com/events
Status: 304 Not Modified
Source: Memory Cache
Address: 52.215.119.172:443
Initiator: 
xhr.js:178

Request
GET /events HTTP/1.1
Accept: application/json, text/plain, */*
Origin: https://chicha.netlify.app
Accept-Language: en-gb
If-None-Match: W/"c010-APRvUYTowK2az7ovB1dPcY+SGuk"
Host: chicha-api.herokuapp.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Safari/605.1.15
Referer: https://chicha.netlify.app/
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
X-Requested-With: XMLHttpRequest

Response
HTTP/1.1 304 Not Modified
Connection: keep-alive
Access-Control-Allow-Credentials: true
ETag: W/"c010-APRvUYTowK2az7ovB1dPcY+SGuk"
Date: Wed, 03 Jun 2020 10:26:18 GMT
Via: 1.1 vegur
Access-Control-Allow-Origin: https://chicha.netlify.app
Content-Length: 0
Vary: Origin
Server: Cowboy
X-Powered-By: Express

被阻止的请求具有与来源不同的引用者这一事实是否重要?或者可能是 cookie 没有随请求一起发送的问题(尽管withCredentials在 axios 中进行了配置)?

编辑(2020 年 6 月 4 日):我已经能够在 localhost 上复制它,所以我正在编辑以表明这只是 Safari 中的一个问题。鉴于相关问题和一些测试,我认为这与allowedHeaders/ CORSAccess-Control-Allow-Headers配置有关,并且可能与 Safari 配置OPTIONS预检请求的方式有关。即使配置 Reactotron 和 apisauce,我也无法查看所有请求详细信息。

编辑(2020 年 6 月 7 日):所以我注意到 Safari 中没有设置 cookie,所以我在服务器端设置为 express 的 currentUser 没有持久化(在我登录后设置的 req.session.currentUser 中)。此外,虽然我能够在本地主机中的某一时刻产生错误,但我无法在本地可靠地复制它。

标签: node.jssafariaxioscorsaccess-control

解决方案


事实证明,由于 Safari 隐私设置中的“防止跨站点跟踪”选项,Safari 阻止了从我的 API 发送的 cookie。禁用此功能,一切正常。

因此,似乎唯一的解决方法是将 API 放置在与 Web 应用程序相同的域中,或者使用代理,如此问题和答案中所引用: Is there a workaround for Safari iOS "Prevent Cross Site Tracking" option, when从不同域的 API 发出 cookie?


推荐阅读