跨域问题解决方案汇总

news/2025/11/15 21:29:51/文章来源:https://www.cnblogs.com/haoxiugong/p/19226280

全文默认讲的是浏览器端发起的 HTTP 请求的“跨域”问题(同源策略导致的受限)。

跨域 / 同源策略概述

  • 同源(same-origin)​:协议、域名(host)、端口 三者完全相同称为同源。 例如 https://example.com:443http://example.com 不是同源(协议不同)。
  • 同源策略(SOP)​:浏览器的一种安全机制,限制从一个源加载的脚本去读取另一个源的响应(以防 CSRF / 数据泄露)。
  • 跨域(cross-origin)​:当请求目标不满足同源时即为跨域,请求仍可发出,但浏览器会阻止 JS 读取响应,除非服务器明确允许(即 CORS -> 跨域资源共享)。

CORS(Cross-Origin Resource Sharing)

CORS(Cross-Origin Resource Sharing)跨域资源共享。浏览器会根据响应头判断是否允许跨域读取。一些关键的响应头包括:

  • Access-Control-Allow-Origin:允许的源(或 *)。

    但是这里我们一般不配置为 *,因为如果响应包含敏感数据或依赖 cookie/凭证(Authorization / session), *Access-Control-Allow-Credentials: true 不能同用,浏览器也会拒绝这种组合,属于安全漏洞 ⚠️。(篇幅有限,更多细节见下篇文章。)

  • Access-Control-Allow-Methods:允许的方法(GET, POST, PUT...)。
  • Access-Control-Allow-Headers:允许的自定义 Header(如 Authorization, X-Custom-Header)。
  • Access-Control-Allow-Credentials:是否允许带 cookie/凭证(true 表示允许)。
  • Access-Control-Expose-Headers:允许前端访问的响应头。
  • Access-Control-Max-Age:预检(preflight)结果缓存时长(秒)。

    预检请求(preflight):当请求使用了非“简单请求”方法或自定义了 header、或 Content-Type 非简单类型时,浏览器会先发 OPTIONS 请求询问服务器是否允许。

常见解决方案

方案 A — 在服务端正确配置 CORS

这是最通用也最推荐的做法:​在响应里返回正确的 CORS 头​。

Express(Node)示例(使用 cors 中间件)

const express = require('express')
const cors = require('cors')
const app = express()app.use(cors({origin: 'https://app.example.com', // 注意不能用 '*' 配合 credentialsmethods: ['GET','POST','PUT','DELETE','OPTIONS'],credentials: true, // 允许 cookieallowedHeaders: ['Content-Type','Authorization','X-Requested-With']
}));

Nginx:把 CORS header 加到响应上

location /api/ {if ($request_method = 'OPTIONS') {add_header 'Access-Control-Allow-Origin' 'https://app.example.com';add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS,PUT,DELETE';add_header 'Access-Control-Allow-Headers' 'Authorization,Content-Type';add_header 'Access-Control-Allow-Credentials' 'true';add_header 'Access-Control-Max-Age' 1728000;add_header 'Content-Length' 0;add_header 'Content-Type' 'text/plain charset=UTF-8';return 204;}proxy_pass http://backend;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;# 把 header 添加到后端响应proxy_hide_header 'Access-Control-Allow-Origin';add_header 'Access-Control-Allow-Origin' 'https://app.example.com';add_header 'Access-Control-Allow-Credentials' 'true';
}

方案 B — 前端代理到同源(仅开发阶段)

开发阶段或没有后端权限时使用我们经常使用构建工具的 dev server 实现反向代理。把跨域请求代理到本地 dev server(同源),由 dev server 转发到目标服务器。

Vite dev server 配置

// vite.config.js
export default {server: {proxy: {'/api': {target: 'https://api.example.com',changeOrigin: true,rewrite: path => path.replace(/^\/api/, '')}}}
}

方案 C — Nginx 反向代理(生产阶段常用)

这也是生产环境下的常用方案。在 Nginx 等反向代理层统一转发,前端调用同域(Nginx),Nginx 代理后再与后端跨域通信。

前端请求:https://app.example.com/api/...(同源) Nginx proxy_pass -> https://api.example.com/...

server {listen 80;server_name example.com;# 静态资源代理location /static/ {root /project/static;index index.html index.html; # 访问 /static/ 会自动“重定向”到 /project/static/index.html 文件}# API代理location /api/ {rewrite ^/api/(.*)$ /$1 break; # 如果服务器没有 /api 记得重写proxy_pass http://api.example.com; # 代理的地址}
}

方案 D — JSONP(已过时,仅限 GET)

只支持 GET,通过 <script> 标签绕过 SOP,服务端返回 callback(...),容易被攻击者使用 callback 恶意函数做 XSS 攻击。

方案 E — postMessage(跨窗口/iframe 场景)

当需要跨域页面间通信(iframe 和父窗口),使用 window.postMessage。适用于页面间数据交换,不适用于普通 API 请求。我们一般会在微前端、OAuth 第三方登录、单点登录、支付页面回调、WebView 混合开发中使用。

方案 F — WebSocket(不受 CORS 限制)

WebSocket 握手不是标准的 CORS;如果用 WS/WSS,浏览器不会因同源限制阻止读取消息(但服务器可能做 origin 校验)。我们也不可能为了跨域强行使用 WebSocket。(之后会详细介绍 HTTP 协议和 WebSocket 协议关系和他们的使用)

开发时一些坑

在我刚开始独立从零到一搭建前后端项目的时候(当时还没有什么 AI Coding,全凭一手搜索引擎),这个问题让我红温到晚上一点也没有解决(没错,当时我还很菜 hh)。

  1. 服务端:
    1. Access-Control-Allow-Origin: https://app.example.com(具体 origin,不能是 *
    2. Access-Control-Allow-Credentials: true
  2. 前端(fetch / xhr):
    1. fetch(url, { credentials: 'include' })xhr.withCredentials = true

当时我犯的错误​:

  • 没有设置 credentials: 'include',浏览器不会发送 cookie。
  • 服务端回送 Access-Control-Allow-Origin: *Allow-Credentials: true 同时存在(浏览器会拒绝)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/966511.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Access-Control-Allow-Origin 在企业中的用法

接上篇文章说道,跨域解决方案中的 CORS 方案,会配置一个 Access-Control-Allow-Origin 的配置项,而且我们一般不直接配置为 *,这样做的原因是什么以及企业中的最佳实践是怎么样的,这篇文章给你答案!简单概括Acce…

VUE_basic - Ref

vue Vue 官方文档: https://vuejs.org/ 1.vue_basic 01_初识Vue <!DOCTYPE html> <html><head><meta charset="UTF-8" /><title>初识Vue</title><!-- 引入Vue --…

详细介绍:像素退场,曲线登场:现代响应式 CSS 全家桶 | 领码课堂

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

HTTPS 究竟比 HTTP 好在哪?

一、HTTP vs HTTPS 概览 HTTPS = HTTP + 加密认证(基于 TLS),能防止被中间人窃听与篡改,并证明服务器身份。非对称(RSA/ECDSA)用于​做身份认证与安全协商密钥​(但慢)。 对称加密速度快,适合实际数据传输。 …

小苯的因子查询

题目链接:https://www.nowcoder.com/practice/6a22a725087b4a11a1aad4fd170d1c6b?channelPut=trackerqcq12 思路解法: 武功秘籍:《阶乘因子心法》 第一层心法:核心洞察(为什么是质因子『2』?) 口诀一: “问奇…

详细介绍:MongoDB 自动化脚本安装方案

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

Linux网络--6、网络层 - 详解

Linux网络--6、网络层 - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco"…

原型理解从入门到精通

原型这块知识点,其实在我们工作中的使用非常简单。但是俗话说“面试造火箭,工作拧螺丝”,在面试中,面试官不时就会考察一些花里胡哨的问题,所以,我们只有将这个概念和他的相关知识理解透彻,才能以不变应万变。两…

2025-11-15

Problem - 1858B - Codeforces(1500)(贪心) 这题一个是要读题 在不包括cookie seller的区间才算没吃饼干的时间sum += (s[i] - s[i - 1] - 1) / d; 在加上路过cookie seller时吃的饼干数 sum += m - 1; 然后贪心的…

Pandas - read_html()

Pandas - read_html()When I ran below code: df = pd.read_html(https://en.wikipedia.org/wiki/List_of_countries_by_population) I got error: HTTPError: HTTP Error 403: Forbidden I can open that URL in brow…

实用指南:Linux企业级解决方案架构:字节跳动短视频推荐系统全链路实践

实用指南:Linux企业级解决方案架构:字节跳动短视频推荐系统全链路实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: …

实用指南:PyTorch DataLoader 高级用法

实用指南:PyTorch DataLoader 高级用法2025-11-15 20:48 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block …

简单做一个舒尔特方格小游戏

以下是一个 Python 简易舒尔特方格小游戏,基于 tkinter 实现(无需额外安装第三方库),支持自定义方格大小、计时计分、自动生成随机数字,新手可直接复制运行: 舒尔特方格小游戏(Python 代码) `import tkinter a…

C语言新手怎么快速掌握

C 语言新手快速掌握的核心逻辑是:先抓核心语法(少而精),再练动手实战(高频场景),最后补底层原理(避免踩坑),全程围绕 “用代码解决实际问题” 展开,拒绝死记硬背。以下是 4 周可落地的学习方案,兼顾效率和…

RSS and Atom

RSS and AtomWhat is RSS? ChatGPT said:RSS (Really Simple Syndication) is a standard web format used to publish frequently updated content, such as news articles, blog posts, podcasts, and announcement…

Wi-Fi FTM(Fine Timing Measurement)简介

1. 什么是 Wi-Fi FTM? Wi-Fi FTM(Fine Timing Measurement)是 IEEE 802.11mc 标准中引入的一项精确测距技术。它通过 Wi-Fi 设备之间的多次往返时间(Round-Trip Time, RTT)测量,计算两者之间的距离,从而实现室内…

通用会话控制方案

一、会话控制概念目的:在无状态的 HTTP 请求间识别/鉴权用户身份并维持登录状态。 核心问题:谁保存“用户状态”?(服务器 / 客户端 / 第三方认证服务器),以及如何安全地在多请求间传递该凭证(Cookie / Authoriz…

LISTAGG 用于将多行数据聚合为单行字符串(拼接),而与其功能相反的需求是 将单行字符串按指定分隔符拆分为多行数据

LISTAGG 用于将多行数据聚合为单行字符串(拼接),而与其功能相反的需求是 将单行字符串按指定分隔符拆分为多行数据。Oracle 中没有直接对应的内置内置函数**,但可以通过以下方法实现类似效果: 方法1:使用 CONNEC…

ESP32 I2S音频总线学习笔记(八):添加按键控制功能 - 详解

ESP32 I2S音频总线学习笔记(八):添加按键控制功能 - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Conso…