跨域问题常遇常新,每次都觉得再也不会有问题了,结果过几天又会掉进新坑。
因为种种原因,最近一个项目需要跨域请求 API。然后就随手设置了一下,结果 GET
没问题,POST
就不行,很明显是撞到跨域墙上了。
最后发现原因:
- 我们启用了 basic auth 验证用户身份
OPTIONS
也会被要求验证- 预请求失败,后面的正式请求就不会发出
趁着还没忘,总结一下跨域的处理过程:
- 首先,熟读《MDN HTTP访问控制(CORS)》
- 跨域时,复杂请求(除
HEAD
、GET
、POST
) API 需要返回 CORS 头 - 发起复杂请求前,会发送一个 preflight 请求,也就是
OPTIONS
,很多坑都在这个请求上 OPTIONS
是浏览器自动发送的,不受我们控制,在开发者工具的 Network 面板里也看不到。我们经常需要模拟它,检查返回是否符合预期。请求头在后面。OPTIONS
无法处理 Basic auth,如果开了的话,要做特殊处理- 需要返回
Access-Control-Allow-Origin
允许跨域的域名,简单点可以写*
,但如果要上传 cookie(withCredential: true
),则必须写明域名,且只能是 一个 域名 - 所以如果有多个域名要跨域访问 API,需要在服务器端判断来源,并返回不同的域名
- 如果要上传 cookie,需要在请求时声明
withCredential: true
- 服务器还要返回许可的方法,即
Access-Control-Allow-Methods: GET, DELETE, PATCH
等,让浏览器判断 - 如果前面都通过了,浏览器才会发送正式请求。如果正式请求失败,则看不到任何返回。
测试 OPTIONS 请求头
OPTIONS /resource/foo
Access-Control-Request-Method: DELETE
Access-Control-Request-Headers: origin, x-requested-with
Origin: https://foo.bar.org
欢迎吐槽,共同进步