作者:watermelo37
涉及领域:Vue、SpingBoot、Docker、LLM、python等
---------------------------------------------------------------------
温柔地对待温柔的人,包容的三观就是最大的温柔。
---------------------------------------------------------------------
编辑
剖析跨域问题始末及其解决方案——前端必备交叉知识(一)
编辑
在前端开发的旅程中,跨域问题无疑是一道难以逾越的高山。无论是初入职场的新手,还是经验丰富的老手,都可能在这座山前止步不前。跨域问题不仅在调试阶段频繁出现,更在正式环境的部署中如影随形,让开发人员头疼不已。今天,就让我们一起深入探讨跨域问题的根源,剖析其表现形式,并逐一攻克常见的跨域难题。希望这篇文章能成为你的指南,帮助你全面理解跨域及其解决方案,提升解决实际问题的能力。
一、同源策略与跨域
1、什么是同源策略
同源策略(Same-Origin Policy) 是浏览器的一种安全机制,目的是为了防止不同来源的文档和脚本相互干扰,避免潜在的安全问题。根据同源策略,同源的资源可以自由交互,而异源的资源则受到严格限制。
同源的定义是:
源(origin) = 协议 + 域名(ip地址) + 端口
比如百度的首页链接与搜索“跨域”词条后的链接属于同源,他们的源都是https://www.baidu.com(协议 + 域名 + 端口)
搜索“跨域”词条:https://www.baidu.com/s?wd=%E8%B7%A8%E5%9F%9F&ie=UTF-8&tn=40020637_15_oem_dg&ch=1
编辑
编辑
而百度(https://www.baidu.com/)和百度图片(https://image.baidu.com/)就是异源的,因为域名不同。
我们在开发中同时启动的前后端项目,假如分别为:http://localhost:8080和http://localhost:8081,它们也是异源的,因为端口号不同。
还有一种情况就是协议不同,http、https、ws(websocket),这三种常见的协议相互之间都是异源的。
2、违背同源策略(即跨域)会怎么样?
跨域问题通常发生在你希望从一个域名(比如前端应用)访问另一个域名(比如后端API)时,浏览器会阻止这一行为,除非目标服务器显式声明允许跨域请求。最常见的跨域请求场景是使用 AJAX 向后端API发起请求。
二、为什么会有跨域问题?
1、同源策略的设计初衷
同源策略(Same-Origin Policy)是浏览器的一个核心安全机制,目的是为了防止恶意网站从用户的浏览器中窃取敏感信息。例如,假设用户在银行网站登录,其浏览器的身份验证信息可能会被一个恶意网站请求并滥用。为了防止这种情况,浏览器就强制实施了同源策略。
简单点说,你的浏览器会保留很多缓存数据,登录的token也不会立即失效,如果没有同源策略,那么你访问一些特殊的网站,它就可以偷偷读取你其他网站的信息,泄露隐私甚至造成财产经济损失。
2、浏览器如何识别跨域?
当你从一个页面发起请求(如 AJAX 请求),浏览器会首先检查请求的目标是否与当前页面同源。如果目标是异源,浏览器就会阻止该请求,除非目标服务器明确表示允许跨源请求。这也是为何跨域请求会在开发中带来困扰。
三、现代跨域的解决方案——CORS
CORS(Cross-Origin Resource Sharing,跨域资源共享)是解决跨域问题的现代标准,广泛应用于当今的前端开发中。
1、CORS 的基本工作原理
CORS 允许服务器通过 HTTP 响应头来声明哪些源可以访问资源。当浏览器发现目标服务器支持 CORS 时,会发起跨域请求,并在请求头中包含一个 Origin 字段。服务器返回的响应中需要包含 Access-Control-Allow-Origin 字段,告知浏览器该请求是否被允许。
2、CORS 过程
简单请求:当请求方法是 GET、POST 或 HEAD;请求头符合安全规范(浏览器默认头部字段均符合安全规范,但手动修改后就可能会打破);并且如果有Content-Type,其值必须为“text/plain”、“multipart/form-data”、“application/x-www-form-urlencoded”这三个中的一个。满足以上三个条件,浏览器会直接发出请求。
下方两个案例分别违反了“请求头符合安全规范”和“Content-Type值类型只能是上述三种之一”的限制要求:
// 修改了请求头 fetch("https://douyin.com", { headers: { a: 1, }, }); // content-type的值类型不属于“text/plain”、“multipart/form-data”、“application/x-www-form-urlencoded”这三个中的一个 fetch("https://douyin.com", { method: "POST", headers: { "content-type": "application/json", }, body: JSON.stringify({ a: 1, b: 2 }), });
预检请求:如果请求不符合简单请求的条件,浏览器会先发起一个 OPTIONS 请求(预检请求),询问服务器是否允许此类跨域操作。如果服务器返回允许的响应头,浏览器才会继续发起实际的请求。
3、CORS 响应头
- Access-Control-Allow-Origin:指定哪些源可以访问资源,可以是具体的域名或
*
(允许所有源)。 - Access-Control-Allow-Methods:指定允许的 HTTP 方法,如 GET、POST、PUT 等。
- Access-Control-Allow-Headers:指定允许的请求头。
- Access-Control-Allow-Credentials:如果请求需要携带凭证(如 Cookies),则需要设置为 true。
4、关于Cookie 与身份凭证
在跨域请求中,默认情况下,浏览器不会发送 Cookie。如果需要发送身份凭证(如 cookie、session),则需要设置以下选项:
// xhr var xhr = new XMLHttpRequest(); xhr.withCredentials = true; // fetch api fetch(url, { credentials: "include", });
服务器也需要在响应中明确设置:
Access-Control-Allow-Credentials: true
需要特别注意的是,不能设置 Access-Control-Allow-Origin: *,如果是携带凭证的跨域请求,源必须明确指定。
5、关于跨域情况下的响应头
在跨域访问时,JS 只能拿到一些最基本的响应头,如:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma,如果要访问其他头,则需要让服务器把允许浏览器访问的头放入白名单,例如:
Access-Control-Expose-Headers: authorization, otherHeaders
四、代理:中间人的妙用
1、代理解决跨域
如果无法修改目标服务器的 CORS 设置,另一种常见的解决方案是使用代理。代理服务器充当前端与目标服务器之间的中介,接受来自前端的请求,转发给目标服务器,再将响应返回给前端。
这种方式通常有两种形式:
- 开发环境代理:在开发时使用本地代理服务器(如 webpack-dev-server 或 vite)解决跨域问题。
- 生产环境代理:在生产环境中,部署一个专门的代理服务器,转发请求。
代理的优点是,它无需目标服务器支持 CORS,但也有一些缺点,比如增加了额外的性能开销,代理增加了请求的响应时间;同时维护复杂,需要额外维护代理服务器。
2、代理的示例
在 vite 中配置代理:
// vite.config.js export default { server: { proxy: { '/api': '你允许的可跨域的源', }, }, };
五、JSONP:传统的跨域解决方案
1、JSONP 的工作原理
JSONP(JSON with Padding)是一个较早的解决跨域问题的技术。通过动态插入一个 <script> 标签,浏览器可以绕过同源策略,因为 <script> 标签可以跨域加载资源。JSONP 的核心思想是通过回调函数传递数据。
2、JSONP 的缺点
仅支持 GET 请求:由于 <script> 标签只能发起 GET 请求,JSONP 无法支持其他 HTTP 方法(如 POST)。
安全问题:JSONP 通过执行返回的 JavaScript 代码来获取数据,这可能带来 XSS(跨站脚本攻击)的风险。
由于安全问题,JSONP 现在基本上已被 CORS 所取代,除非没有其他选择,否则不应使用。
六、如何选择合适的跨域解决方案?
选择跨域解决方案时,主要考虑以下因素:
是否能控制目标服务器:如果能控制目标服务器的 CORS 配置,推荐使用 CORS。
是否只需要 GET 请求:如果只能使用 GET 请求并且目标服务器不支持 CORS,考虑使用 JSONP。
开发和生产环境的兼容性:开发环境通常可以使用代理来解决跨域问题,而生产环境则需要考虑使用反向代理或 CORS。
这里有一份决策图,可以辅助参考如何选择合适的跨域解决方案,其关键在于控制生产环境和开发环境一致,否则部署的时候依然会出现跨域问题:
编辑
七、总结
跨域问题是前端开发中的常见挑战,了解并掌握不同的跨域解决方案能帮助你更高效地进行开发工作。本文对同源策略、跨域以及解决跨域的三种方案: CORS、JSONP、代理等跨域技术进行了介绍。选择合适的跨域解决方案非常重要。
在实际开发中,推荐优先考虑使用 CORS,因为它是现代浏览器支持的标准,且安全性较高。如果服务器无法修改,则可以考虑使用代理。如果是特殊情况,可以使用 JSONP,但要注意安全性。
只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
其他热门文章,请关注:
极致的灵活度满足工程美学:用Vue Flow绘制一个完美流程图
你真的会使用Vue3的onMounted钩子函数吗?Vue3中onMounted的用法详解
通过array.filter()实现数组的数据筛选、数据清洗和链式调用
通过Array.sort() 实现多字段排序、排序稳定性、随机排序洗牌算法、优化排序性能
通过MongoDB Atlas 实现语义搜索与 RAG——迈向AI的搜索机制
TreeSize:免费的磁盘清理与管理神器,解决C盘爆满的燃眉之急
深入理解 JavaScript 中的 Array.find() 方法:原理、性能优势与实用案例详解
el-table实现动态数据的实时排序,一篇文章讲清楚elementui的表格排序功能
MutationObserver详解+案例——深入理解 JavaScript 中的 MutationObserver
Dockerfile全面指南:从基础到进阶,掌握容器化构建的核心工具