网站首页 > 技术文章 正文
当你在浏览器控制台看到那串刺眼的红色错误——"Access to XMLHttpRequest at 'https://api.example.com' from origin 'https://yourwebsite.com' has been blocked by CORS policy",是不是瞬间感觉头皮发麻?这个被前端开发者戏称为"跨域魔咒"的问题,其实背后藏着浏览器最严格的安全卫士——同源策略。今天咱们就来扒开这个"保安系统"的工作手册,让你下次遇到CORS错误时能淡定地说:"小场面,我知道怎么搞定"。
浏览器的"门禁系统":同源策略到底在防什么?
现代浏览器就像个戒备森严的写字楼,每个网页都是一间办公室。同源策略就是这里的门禁规则:只有协议、域名、端口三者完全相同的"访客"(请求)才能自由通行。举个例子,
https://www.example.com:443和http://www.example.com:80虽然只差一个s和端口号,在浏览器眼里就是两个完全不同的"公司",想要串门?没门!
你可能会问:"浏览器至于这么较真吗?"还真至于。没有同源策略的保护,黑客的脚本可以轻松读取你银行账户页面的Cookie,或者伪装成你在社交网站上发帖。2018年某电商平台就因同源策略配置不当,导致用户收货地址被恶意网站获取,这个教训至今让开发者记忆犹新。
CORS:给跨域请求办"通行证"
既然同源策略这么严格,那不同网站之间怎么合法交流?这就需要CORS(跨域资源共享)这个"通行证系统"登场了。简单说,CORS就是服务器告诉浏览器:"这个域名的请求我认,你让它进来吧"。
但浏览器这个"保安"特别谨慎,不是所有请求都直接放行。它会把请求分成两类:
- 简单请求:像GET、POST这类"老实本分"的请求,会直接发送,服务器在响应头里加上Access-Control-Allow-Origin: https://yourwebsite.com就行
- 预检请求:如果请求带了自定义头或者用了PUT、DELETE等"特殊动作",浏览器会先派个"侦察兵"(OPTIONS请求)去问服务器:"我这请求能过不?"服务器同意后才会发送真正的请求
这个过程就像你去别人家做客:简单请求是"打个招呼就进门",预检请求则是"先打电话问问主人在不在家"。
那些年我们踩过的CORS坑
就算懂了原理,实际开发中还是会被CORS折磨得怀疑人生。看看这些经典错误你是不是似曾相识:
No '
Access-Control-Allow-Origin' header:这是最常见的"拦路虎"。后端开发者拍着胸脯说"我配了啊",结果一看代码——
Access-Control-Allow-Origin设成了*却同时用了Cookie,浏览器直接判定"通行证无效"。记住:带Cookie的跨域请求,服务器必须明确指定域名,不能用通配符。
预检请求被拒绝:前端开发者兴冲冲写了个带X-Token头的请求,结果控制台报错。原因很简单:服务器没在
Access-Control-Allow-Headers里加上这个自定义头,就像你拿着门禁卡却忘了录指纹。
凭据丢失问题:明明前端设置了withCredentials: true,服务器也配了Allow-Credentials,请求还是失败。这时不妨看看服务器是不是同时设置了
Access-Control-Allow-Origin: *——浏览器规定,带凭据的请求和通配符域名是水火不容的。
搞定CORS的实战秘籍
解决CORS问题就像开锁,找对钥匙很重要。这里有几套"万能钥匙"供你选择:
后端配置是根本:不管前端怎么折腾,最终还得靠服务器松口。不同语言有不同的配置方式,但核心都是设置那几个关键响应头:
- Node.js(Express):
app.use((req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', 'https://yourwebsite.com');
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-Token');
  res.setHeader('Access-Control-Allow-Credentials', 'true');
  next();
});- Java(Spring Boot):
@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("https://yourwebsite.com")
                .allowedMethods("*")
                .allowedHeaders("*")
                .allowCredentials(true);
    }
}前端代理是权宜之计:开发环境下,用Webpack或Vite配置代理服务器,把跨域请求伪装成同源请求:
// vite.config.js
export default defineConfig({
  server: {
    proxy: {
      '/api': {
        target: 'https://api.example.com',
        changeOrigin: true,
        rewrite: path => path.replace(/^\/api/, '')
      }
    }
  }
})JSONP是老古董:虽然只能支持GET请求,但在某些奇葩环境下(比如IE8),JSONP还是能救急。原理就是利用<script>标签不受同源策略限制的特性,不过现在已经基本被CORS取代了。
生产环境的CORS最佳实践
上线前这些细节千万不能忽略:
- 别用通配符:明确指定允许的域名,Access-Control-Allow-Origin: *虽然省事,但就像给大楼所有门都配了一把钥匙
- 限制请求方法:别偷懒写allowedMethods: "*",只开放需要的HTTP方法
- 预检缓存:设置Access-Control-Max-Age缓存预检请求结果,减少不必要的OPTIONS请求
- CDN也要配置:如果静态资源放在CDN上,别忘了在CDN控制台也配置CORS规则
浏览器的同源策略就像一把双刃剑,既保护了用户安全,也给开发者添了不少麻烦。但只要搞懂它的工作原理,掌握CORS的配置技巧,下次再遇到跨域错误,你就能像拆弹专家一样从容应对。记住,每个红色的CORS错误提示背后,都藏着浏览器默默守护安全的良苦用心——虽然这份守护有时确实让人想砸键盘。
猜你喜欢
- 2025-09-14 前端上传切片优化以及实现_页面切片上传
- 2025-09-14 黑客通过钓鱼攻击劫持npm软件包:含chalk、debug等十余个高频库
- 2025-09-14 记录一次网盘资源不给提取码的经历!另类编程思维,Python破之!
- 2025-09-14 前端必读:如何在 JavaScript 中使用SpreadJS导入和导出 Excel 文件
- 2025-09-14 面试官:说说你对options请求的理解
- 2025-09-14 手把手教你写一个简易的微前端框架
- 2025-09-14 腾讯工程师案例实战:大型前端项目的断点调试共享化和复用化实践
- 2025-09-14 js 通过流的方式进行下载_js 下载流文件
- 2025-09-14 如何在关闭浏览器标签前,可靠地发送 HTTP 请求?
- 2025-07-09 跨域资源的共享(CORS)N种用法(跨域资源共享的缩写是?)
- 最近发表
- 
- 聊一下 gRPC 的 C++ 异步编程_grpc 异步流模式
- [原创首发]安全日志管理中心实战(3)——开源NIDS之suricata部署
- 超详细手把手搭建在ubuntu系统的FFmpeg环境
- Nginx运维之路(Docker多段构建新版本并增加第三方模
- 92.1K小星星,一款开源免费的远程桌面,让你告别付费远程控制!
- Go 人脸识别教程_piwigo人脸识别
- 安卓手机安装Termux——搭建移动服务器
- ubuntu 安装开发环境(c/c++ 15)_ubuntu安装c++编译器
- Rust开发环境搭建指南:从安装到镜像配置的零坑实践
- Windows系统安装VirtualBox构造本地Linux开发环境
 
- 标签列表
- 
- cmd/c (90)
- c++中::是什么意思 (84)
- 标签用于 (71)
- 主键只能有一个吗 (77)
- c#console.writeline不显示 (95)
- pythoncase语句 (88)
- es6includes (74)
- sqlset (76)
- apt-getinstall-y (100)
- node_modules怎么生成 (87)
- chromepost (71)
- flexdirection (73)
- c++int转char (80)
- mysqlany_value (79)
- static函数和普通函数 (84)
- el-date-picker开始日期早于结束日期 (76)
- js判断是否是json字符串 (75)
- c语言min函数头文件 (77)
- asynccallback (87)
- localstorage.removeitem (77)
- vector线程安全吗 (73)
- java (73)
- js数组插入 (83)
- mac安装java (72)
- 无效的列索引 (74)
 
