JS同源策略和跨域问题深入分析和解决

 更新时间:2025年02月03日 11:57:58   作者:秋水为渡  
这篇文章主要介绍了JS同源策略和跨域问题深入分析和解决,在Web开发中,跨域问题是一个常见且必须解决的难题,当浏览器出于安全考虑限制不同源之间的资源交互时,开发者需要掌握多种方案来绕过这些限制,需要的朋友可以参考下

引言-跨域问题的本质与挑战

在Web开发中,跨域问题是一个常见且必须解决的难题。当浏览器出于安全考虑限制不同源之间的资源交互时,开发者需要掌握多种方案来绕过这些限制。本文将系统性地解析同源策略的核心机制,并提供几种跨域解决方案的实现细节与最佳实践。

一、同源策略-浏览器的安全基石

1. 同源的定义

同源策略(Same-Origin Policy)是浏览器的核心安全机制,要求两个URL的以下三个部分完全一致才能被视为“同源”:

协议(Protocol):如httphttps不同源。

域名(Domain):如a.example.comb.example.com不同源。

端口(Port):如example.com:80example.com:8080不同源。

2. 同源策略的限制范围

AJAX请求:默认禁止跨域请求(XMLHttpRequest、Fetch API)。

DOM访问:禁止跨域访问iframe内的contentWindow

存储数据:禁止读取跨域的CookieLocalStorage等数据。

脚本与资源加载:允许加载跨域资源(如<script><img>),但限制访问其内容。

3. 为什么需要同源策略

安全防护:防止恶意网站通过脚本窃取用户敏感数据(如Cookie)。

隔离风险:避免跨站脚本攻击(XSS)和跨站请求伪造(CSRF)。

二、跨域解决方案详解

1. CORS(跨域资源共享)

原理:通过后端设置HTTP响应头,显式允许指定源的请求。

适用场景:生产环境首选方案,支持所有HTTP方法。

实现步骤:

简单请求(GET/POST/HEAD且无自定义头):

后端返回Access-Control-Allow-Origin头。

// 后端示例(Node.js/Express)
res.setHeader('Access-Control-Allow-Origin', 'https://your-frontend.com');

预检请求(复杂请求如PUT/DELETE或带自定义头):
后端需处理OPTIONS预检请求,并返回允许的方法和头信息。

// 处理预检请求
app.options('/api', (req, res) => {
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  res.status(204).end();
});

注意事项:

避免使用Access-Control-Allow-Origin: *,需明确指定可信源。

携带Cookie时需设置Access-Control-Allow-Credentials: true,且前端开启credentials: 'include'

2. JSONP(JSON with Padding)

原理:利用<script>标签不受同源策略限制的特性,通过回调函数获取数据。
适用场景:仅支持GET请求,适用于老旧浏览器或简单数据获取。

实现步骤:

前端定义回调函数并动态创建<script>标签。

function handleResponse(data) {
  console.log('Received:', data);
}
const script = document.createElement('script');
script.src = 'https://api.example.com/data?callback=handleResponse';
document.body.appendChild(script);

后端返回包裹在回调函数中的JSON数据。

// 后端返回格式
handleResponse({ "status": "success", "data": [...] });

局限性:

仅支持GET请求。

存在XSS风险,需确保后端可信。

3. 代理服务器

原理:通过同源的后端服务转发请求,绕过浏览器限制。
适用场景:前端开发环境调试,或后端无法修改CORS配置时。

实现方式:

开发环境代理(Webpack/Vite):

// vite.config.js
export default {
  server: {
    proxy: {
      '/api': {
        target: 'https://api.example.com',
        changeOrigin: true,
      }
    }
  }
};

生产环境Nginx反向代理:

server {
  location /api/ {
    proxy_pass https://api.example.com/;
    proxy_set_header Host $host;
  }
}

4. WebSocket

原理:WebSocket协议不受同源策略限制,支持双向通信。
适用场景:实时通信应用(如聊天室、实时数据推送)。

实现示例:

const socket = new WebSocket('wss://api.example.com');
socket.onmessage = (event) => {
  console.log('Received:', event.data);
};

5. postMessage API

原理:允许跨域的window对象间安全通信。
适用场景:跨域iframe通信或跨窗口数据传递。

实现步骤:

发送方窗口

const targetWindow = document.getElementById('iframe').contentWindow;
targetWindow.postMessage('Hello from parent!', 'https://child-domain.com');

接收方窗口

window.addEventListener('message', (event) => {
  if (event.origin !== 'https://parent-domain.com') return;
  console.log('Received:', event.data);
});

6. document.domain

原理:通过设置相同的一级域名实现跨子域通信。
适用场景:同一主域下的不同子域(如a.example.comb.example.com)。

实现步骤:

双方页面设置:

document.domain = 'example.com';

限制:仅适用于同一主域,且已被现代浏览器逐渐弃用。

7. 图像Ping

原理:利用<img>标签的src属性发送简单GET请求。
适用场景:统计打点或单向数据上报。

实现示例:

const img = new Image();
img.src = 'https://api.example.com/track?event=page_view';

三、跨域方案选型指南

方案适用场景优点缺点
CORS生产环境API接口标准化、支持所有HTTP方法需后端配合
JSONP简单数据获取(仅GET)兼容老旧浏览器安全性低、仅支持GET
代理服务器开发环境调试无需修改后端代码生产环境需维护代理服务
WebSocket实时双向通信高性能、支持跨域需后端支持WebSocket协议
postMessage跨窗口/iframe通信安全可控需明确目标窗口引用

四、安全实践与注意事项

  • CORS配置安全:避免使用Access-Control-Allow-Origin: *,严格限制可信源。
  • CSRF防护:即使使用CORS,仍需通过Token或SameSite Cookie防范CSRF攻击。
  • 内容安全策略(CSP):限制外部脚本加载,降低XSS风险。

五、总结

跨域问题的本质是浏览器为保护用户安全而设计的限制,开发者需根据实际场景选择合适方案。对于现代Web应用,CORS与反向代理是生产环境首选,而JSONP和postMessage可作为特定场景的补充。

以上就是JS同源策略和跨域问题深入分析和解决的详细内容,更多关于JS同源策略和跨域的资料请关注脚本之家其它相关文章!

相关文章

  •  javascript学数组中的foreach方法和some方法

     javascript学数组中的foreach方法和some方法

    这篇文章主要介绍了 javascript学数组中的foreach方法和some方法,文章相关内容和代码详细,具有一定的参考价值,需要的小伙伴可以参考一下,希望对你的学习有所帮助
    2022-03-03
  • webpack热模块替换(HMR)/热更新的方法

    webpack热模块替换(HMR)/热更新的方法

    模块热替换(HMR)的作用是,在应用运行时,无需刷新页面,便能替换、增加、删除必要的模块,本篇文章主要介绍了webpack热模块替换(HMR)/热更新的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-04-04
  • JS利用时间戳倒计时的实现示例

    JS利用时间戳倒计时的实现示例

    这篇文章主要介绍了JS利用时间戳倒计时的实现示例,本文将提供代码示例和详细的步骤,帮助你实现一个简单而实用的时间戳倒计时,感兴趣的可以了解一下
    2023-12-12
  • js 判断一个元素是否在页面中存在

    js 判断一个元素是否在页面中存在

    js 判断一个元素是否存在此功能在项目中很实用,本人搜集整理了一些常用技巧,需要了解的朋友可以参考下
    2012-12-12
  • 详解JavaScript UTC时间转换方法

    详解JavaScript UTC时间转换方法

    这篇文章主要介绍了JavaScript UTC时间转换方法,介绍了本地时间到UTC时间的转换、UTC日期到本地日期的转换,感兴趣的小伙伴们可以参考一下
    2016-01-01
  • 十个优秀的Ajax/Javascript实例网站收集

    十个优秀的Ajax/Javascript实例网站收集

    今天,要向大家推荐10个相当棒的Ajax和Javascript国外资源网站或博客,它们提供了相当多的高质量Ajax、Javascript实例及教程,喜欢Ajax和Javascript的朋友绝对不能错过。
    2010-03-03
  • 使用js如何实现全选与全不选

    使用js如何实现全选与全不选

    全选与全不选在管理界面还是比较实用的,下面通过checkAll与clearAll两个函数来轻松实现,感兴趣的朋友不要错过
    2013-12-12
  • js实现对table的增加行和删除行的操作方法

    js实现对table的增加行和删除行的操作方法

    下面小编就为大家带来一篇js实现对table的增加行和删除行的操作方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-10-10
  • 小程序从手动埋点到自动埋点的实现方法

    小程序从手动埋点到自动埋点的实现方法

    这篇文章主要介绍了小程序从手动埋点到自动埋点的实现方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-01-01
  • 在uni-app项目中自定义角标数字键盘弹窗的实现方案

    在uni-app项目中自定义角标数字键盘弹窗的实现方案

    在 uni-app 项目开发中,经常会遇到需要输入角标数字(如下标、上标)的场景(例如化学公式、数学表达式、特殊标注等),因此本文将分享一个自定义角标数字键盘弹窗的实现方案,需要的朋友可以参考下
    2025-11-11

最新评论