为什么禁止我请求别的网站的接口?——跨域与CORS _
你有没有遇到过这种情况在自己的网页上想请求别人的API结果浏览器直接报错Access-Control-Allow-Origin header is missing。为什么浏览器要阻止你服务器不响应不就完了吗今天用小区门禁的故事来讲讲跨域与CORS。什么是跨域同源策略 — 浏览器的安全基石浏览器有个同源策略Same-Origin Policy只有来自同一个家的资源才能随便用。什么叫同一个家看三个条件协议http/https、域名example.com、端口:8080。三个都一样才是同源有一个不一样就是跨域。跨域的例子12345✅ http://example.com 和 http://example.com/profile // 协议域名端口都相同 → 同源✅ https://example.com 和 https://example.com // 协议域名端口都相同 → 同源❌ http://example.com 和 https://example.com // 协议不同 → 跨域❌ http://example.com 和 http://api.example.com // 域名不同子域名→ 跨域❌ http://example.com:8080 和 http://example.com:3000 // 端口不同 → 跨域跨域限制了什么浏览器的同源策略主要限制了三件事DOM 访问无法读取不同源的 iframe 内容、无法修改不同源的 iframe DOMAJAX 请求无法请求不同源的 APICookie/LocalStorage无法访问不同源的数据为什么要限制跨域模拟一个攻击场景想象一下你登录了银行网站浏览器保存了你的登录 Cookie。然后你手滑点进了一个恶意网站这个网站里有一段代码12345form hrefhttps://urlscan.io/result/019dd18e-1f44-74de-a5be-32c1f5ea040c/methodPOSTinput typehiddennametovaluehackerinput typehiddennameamountvalue1000000/formscriptdocument.forms[0].submit();/script如果没有同源策略这个表单请求会自动带上bank.com的 Cookie银行服务器以为是你本人操作的——钱就没了。同源策略就是浏览器的门禁只有同一家人才能进陌生人要查证件。 注意img标签的 GET 请求虽然也会带 Cookie但现代浏览器有SameSiteCookie 保护。上面表单 POST 场景更典型。CORS — 跨域的通行证CORS 是什么CORSCross-Origin Resource Sharing 跨域资源共享。它的工作原理很简单让服务器告诉浏览器我允许来自这些源的请求。简单请求 vs 预检请求简单请求满足以下条件的请求是简单请求简单请求的流程12345671. 浏览器发送请求自动带上 Origin 头↓2. 服务器检查 Origin决定是否允许↓3. 服务器返回响应头 Access-Control-Allow-Origin↓4. 浏览器检查响应头允许就完事服务器端示例Node.js123456789app.get(/api/data, (req, res) {constorigin req.headers.origin;if(origin ) {res.setHeader(Access-Control-Allow-Origin, origin);}res.json({ data:这是返回的数据});});响应头12345HTTP/1.1 200 OKAccess-Control-Allow-Origin: https://example.coma hrefhttps://urlscan.io/result/019dd18e-29e6-702b-b9f9-d2445b252501//aContent-Type: application/json{data:这是返回的数据}预检请求Preflight不满足简单请求条件的浏览器会先发一个 OPTIONS 请求探路12345671. 浏览器发送 OPTIONS 预检请求↓2. 服务器检查方法/头部/Origin↓3. 服务器返回允许的头 Access-Control-*↓4. 浏览器发送实际请求预检请求检查什么预检请求OPTIONS就像登机前的安检——先检查你带没带危险品。浏览器会问服务器三件事我从哪来Origin我想用什么方法Access-Control-Request-Method我想带什么头Access-Control-Request-Headers服务器回答可以浏览器才放行实际请求。1234567891011121314# 请求浏览器发给服务器OPTIONS /api/data HTTP/1.1Origin: a hrefhttps://urlscan.io/result/019dd18e-35a3-76ab-99bf-0752d3378713//a # 我从哪来Access-Control-Request-Method: PUT # 我想用 PUT 方法Access-Control-Request-Headers: Content-Type, Authorization # 我想带这些头---# 响应服务器告诉浏览器HTTP/1.1 204 No ContentAccess-Control-Allow-Origin: a hrefhttps://urlscan.io/result/019dd18e-4068-70d2-a85c-2bfa345b23aa//a # 允许这个源Access-Control-Allow-Methods: GET, POST, PUT, DELETE # 允许这些方法Access-Control-Allow-Headers: Content-Type, Authorization # 允许这些头Access-Control-Max-Age: 86400 # 预检结果缓存24小时服务器端处理123456789101112app.options(/api/data, (req, res) {constorigin req.headers.origin;if(origin a hrefhttps://urlscan.io/result/019dd18e-4c5a-71cc-b20b-a4e8ac2ec164//a) {res.setHeader(Access-Control-Allow-Origin, origin);res.setHeader(Access-Control-Allow-Methods,GET, POST, PUT, DELETE);res.setHeader(Access-Control-Allow-Headers,Content-Type, Authorization);res.setHeader(Access-Control-Max-Age,86400);}res.status(204).send();});CORS 响应头详解常用响应头credentials 模式默认情况下CORS不带Cookie。如果需要携带 Cookie前端123fetch(a hrefhttps://urlscan.io/result/019dd18e-58c4-72c9-b486-e6c5ab731092//a, {credentials:include});服务端12res.setHeader(Access-Control-Allow-Origin, a hrefhttps://urlscan.io/result/019dd18e-64fb-73dd-b51a-0601024a892f//a);res.setHeader(Access-Control-Allow-Credentials,true);注意Access-Control-Allow-Origin不能用*必须是具体域名。跨域的解决方案1. JSONP已不推荐利用script标签不受同源策略限制的特性123456scriptfunction handleData(data) {console.log(data);}/scripta hrefhttps://urlscan.io/result/019dd18e-700f-705d-a721-278d4d15ac80//a2. 代理服务器在自己的服务器上转发请求伪装成同源1浏览器 ── 我的服务器同一源 ── 目标服务器Nginx 代理123location /api/ {a hrefhttps://urlscan.io/result/019dd18f-3875-71a6-a17d-cffb86fc9a00//a;}Node.js 代理12345app.get(/api/data, async (req, res) {constresponse await fetch(a hrefhttps://urlscan.io/result/019dd18f-454d-7307-bbb2-ab0a62f529b5//a);constdata await response.json();res.json(data);});3. Webpack/Vite 开发代理开发环境配置代理1234567891011// vite.config.jsexportdefault{server: {proxy: {/api: {target:http://target-server.com,changeOrigin:true}}}};4. postMessage不同窗口/iframe 之间的通信1234567window.addEventListener(message, (event) {if(event.origin https://example.com) {console.log(收到消息:,event.data);}});iframe.contentWindow.postMessage(hello,https://example.com);深入了解 CORS 第三方 Cookie 的限制现代浏览器正在逐步限制第三方 CookieCORS 和 CSRF 的区别为什么 OPTIONS 叫预检预检就像登机前的安检——先检查你带没带危险品方法、头部没问题了才让你登机发送实际请求。常见错误排查错误 1No Access-Control-Allow-Origin header错误 2Method not allowed错误 3Header not allowed错误 4预检请求 404总结写在最后现在你应该明白了跨域是浏览器的安全机制不是为了刁难你CORS 是服务器授权机制服务器说可以浏览器才放行预检请求 安检OPTIONS 通过了才能发送实际请求生产环境推荐用代理开发环境用 webpack/vite 代理下次遇到跨域错误先看浏览器控制台的报错信息——是缺通行证header 缺失还是通行证不对origin 不匹配处理方式不一样的。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2564900.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!