什么样的请求会触发预检?预检结果能缓存多久?为什么加了 Authorization 头就失败?为什么认证中间件会让预检失败?这篇用真实的 Chrome 与服务端请求日志,把预检的每个细节对照出来。
GET(简单请求) OK 200
POST text/plain(简单请求) OK 200
POST application/json OK 200
POST application/json(再来一次) OK 200
GET + 自定义头 X-Token OK 200
GET + Authorization 头 FAIL Failed to fetch
PUT OK 200
DELETE OK 200
服务端收到的请求顺序: ['GET /data', 'POST /data [text/plain]', 'OPTIONS /data [预检:方法=POST 头=content-type]', 'POST /data [application/json]', 'POST /data [application/json]', 'GET /data', 'OPTIONS /data [预检:方法=GET 头=authorization]', 'OPTIONS /data', 'PUT /data', 'DELETE /data']
其中 OPTIONS 个数: 3上一篇:API 限流;下一篇:ETag API 缓存。
第 79 篇用 Flask-CORS 验证过 CORS 的基本行为,这一篇专门看预检。
GET(简单请求) OK 200
POST text/plain(简单请求) OK 200
POST application/json OK 200
POST application/json(再来一次) OK 200
GET + 自定义头 X-Token OK 200
GET + Authorization 头 FAIL Failed to fetch
PUT OK 200
DELETE OK 200
服务端收到的请求顺序: ['GET /data', 'POST /data [text/plain]', 'OPTIONS /data [预检:方法=POST 头=content-type]', 'POST /data [application/json]', 'OPTIONS /data [预检:方法=POST 头=content-type]', 'POST /data [application/json]', 'OPTIONS /data [预检:方法=GET 头=x-token]', 'GET /data', 'OPTIONS /data [预检:方法=GET 头=authorization]', 'OPTIONS /data', 'PUT /data', 'OPTIONS /data', 'DELETE /data']
其中 OPTIONS 个数: 6 GET(简单请求) OK 200
POST text/plain(简单请求) OK 200
POST application/json FAIL Failed to fetch
POST application/json(再来一次) FAIL Failed to fetch
GET + 自定义头 X-Token FAIL Failed to fetch
GET + Authorization 头 FAIL Failed to fetch
PUT OK 200
DELETE OK 200
服务端收到的请求顺序: ['GET /data', 'POST /data [text/plain]', 'OPTIONS /data [预检:方法=POST 头=content-type]', 'OPTIONS /data [预检:方法=POST 头=content-type]', 'OPTIONS /data [预检:方法=GET 头=x-token]', 'OPTIONS /data [预检:方法=GET 头=authorization]', 'OPTIONS /data', 'PUT /data', 'DELETE /data']
其中 OPTIONS 个数: 5 GET(简单请求) OK 200
POST text/plain(简单请求) OK 200
POST application/json FAIL Failed to fetch
POST application/json(再来一次) FAIL Failed to fetch
GET + 自定义头 X-Token FAIL Failed to fetch
GET + Authorization 头 FAIL Failed to fetch
PUT FAIL Failed to fetch
DELETE FAIL Failed to fetch
服务端收到的请求顺序: ['GET /data', 'POST /data [text/plain]', 'OPTIONS /data [预检:方法=POST 头=content-type]', 'OPTIONS /data [预检:方法=POST 头=content-type]', 'OPTIONS /data [预检:方法=GET 头=x-token]', 'OPTIONS /data [预检:方法=GET 头=authorization]', 'OPTIONS /data', 'OPTIONS /data']
其中 OPTIONS 个数: 6浏览器是本机的 Google Chrome 无头模式,页面与接口是两个不同端口的 gunicorn 服务,CORS 头是手写的(没有用 Flask-CORS)。