JSON是如何跨域的?从原理到实践,一文读懂跨域数据交互
在现代Web开发中,JSON(JavaScript Object Notation)作为一种轻量级的数据交换格式,因其简洁、易读和易于解析的特性,成为前后端数据交互的“通用语言”,由于浏览器的同源策略(Same-Origin Policy)限制,不同源(协议、域名、端口任一不同)的页面无法直接通过JavaScript访问对方的资源,这给JSON数据的跨域获取带来了挑战,JSON究竟是如何“跨越”这些限制,实现跨域数据交互的呢?本文将从原理到实践,详细解析JSON跨域的核心机制与常见方案。
同源策略:JSON跨域的“枷锁”与“钥匙”
要理解JSON如何跨域,首先需要明确同源策略,同源策略是浏览器最核心的安全机制之一,它规定:一个源的文档或脚本不能读取或设置另一个源的文档属性。https://example.com 页面中的JavaScript,无法直接访问 https://api.another-site.com 的数据,即使后者返回的是JSON格式。
但同源策略并非“一刀切”,它区分了“安全”和“不安全”的操作,对于JSON数据交互,浏览器允许通过安全的方式(如跨域资源共享、JSONP等)实现跨域访问,这些方式本质上是浏览器对“可信”跨域请求的“放行”。
JSON跨域的核心方案:从“绕过”到“授权”
JSONP(JSON with Padding):最古老的“跨域漏洞”利用
JSONP是早期解决JSON跨域的主流方案,其核心思想是利用<script>标签的跨域能力,通过动态执行回调函数的方式“绕过”同源策略。
-
原理:
浏览器允许<script>标签加载不同源的JS文件(包括返回JSON数据的接口),JSONP接口返回的不是纯JSON,而是一段调用指定回调函数的JS代码,callbackName({"name": "张三", "age": 18});前端提前定义好
callbackName函数,当<script>标签加载并执行这段代码时,数据就会被传入该函数,从而实现跨域获取。 -
实践步骤:
- 前端定义回调函数:
function handleData(data) { console.log(data); // 输出:{"name": "张三", "age": 18} } - 动态创建
<script>标签,请求JSONP接口(需支持callback参数):const script = document.createElement('script'); script.src = 'https://api.another-site.com/data?callback=handleData'; document.body.appendChild(script); - 服务器返回
handleData({...}),前端自动执行并获取数据。
- 前端定义回调函数:
-
缺点:
- 仅支持GET请求,无法处理POST等复杂请求;
- 存在安全风险(如XSS攻击),需确保接口可信;
- 现代浏览器已逐渐弃用,但部分旧系统仍在使用。
CORS(Cross-Origin Resource Sharing):现代跨域的“标准答案”
CORS是W3C推荐的标准跨域解决方案,通过服务器授权的方式,让浏览器明确允许特定源的请求访问资源,相比JSONP,CORS更安全、更灵活,支持所有HTTP方法(GET、POST、PUT等)。
-
核心机制:
CORS通过HTTP请求/响应中的特殊字段实现跨域控制:- 请求头:前端请求会携带
Origin字段(如Origin: https://example.com),标识请求源; - 响应头:服务器通过响应头告诉浏览器是否允许跨域,关键字段包括:
Access-Control-Allow-Origin:允许的源(如表示所有源,或具体域名https://example.com);Access-Control-Allow-Methods:允许的HTTP方法(如GET, POST, PUT);Access-Control-Allow-Headers:允许的自定义请求头(如Authorization);Access-Control-Allow-Credentials:是否允许携带Cookie(需前端设置credentials: 'include')。
- 请求头:前端请求会携带
-
实践步骤:
-
前端:使用
fetch或XMLHttpRequest发送请求,无需特殊处理(浏览器会自动处理CORS逻辑):fetch('https://api.another-site.com/data', { method: 'GET', headers: { 'Content-Type': 'application/json', }, }) .then(response => response.json()) .then(data => console.log(data)); -
后端:以Node.js(Express)为例,设置CORS响应头:
const express = require('express'); const app = express(); // 允许所有源访问(生产环境建议指定具体域名) app.use((req, res, next) => { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE'); res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization'); next(); }); app.get('/data', (req, res) => { res.json({ name: "李四", age: 20 }); }); app.listen(3000);
-
-
注意事项:
- 简单请求(如GET、POST且Content-Type为
application/x-www-form-urlencoded)会直接发送,服务器响应Access-Control-Allow-Origin即可; - 复杂请求(如带自定义头、PUT/DELETE方法)会先发送预检请求(OPTIONS),服务器需返回
Access-Control-Allow-Methods等字段,浏览器才会发送实际请求; - 跨域携带Cookie时,需设置
Access-Control-Allow-Credentials: true,且前端credentials不能为same-origin。
- 简单请求(如GET、POST且Content-Type为
代理服务器:前端“绕过”同源策略的“中间人”
当前端无法直接修改后端CORS配置时(如调用第三方API),可以通过代理服务器转发请求,实现“同源”交互,代理服务器位于前端和目标服务器之间,将跨域请求转为服务器间的同源请求。
-
原理:
前端请求同源代理接口(如/api/data),代理服务器收到请求后,再转发到目标跨域接口(如https://api.another-site.com/data),最后将目标服务器的响应返回给前端,由于前端与代理服务器同源,浏览器不会拦截请求。 -
实践方案:
-
Nginx反向代理(常用):
server { listen 80; server_name example.com; # 将 /api 请求转发到目标服务器 location /api/ { proxy_pass https://api.another-site.com/; proxy_set_header Host api.another-site.com; proxy_set_header X-Real-IP $remote_addr; } }前端请求
https://example.com/api/data,Nginx会转发到https://api.another-site.com/data,并返回响应。 -
Node.js代理(如
http-proxy-middleware):const express = require('express'); const { createProxyMiddleware } = require('http-proxy-middleware'); const app = express(); // 代理 /api 到目标服务器 app.use('/api', createProxyMiddleware({ target: 'https://api.another-site.com', changeOrigin: true, pathRewrite: { '^/api': '' }, // 重写路径 })); app.listen(3000);
-
-
优点:
- 无需修改后端CORS配置,适合第三方API调用;
- 可统一管理请求(如添加鉴权、日志)。
其他场景:WebSocket与iframe的JSON跨域
-
WebSocket:
WebSocket协议支持跨域,只需在握手阶段通过Origin字段告知服务器,服务器响应后即可建立连接。const ws = new WebSocket('wss://api.another-site.com/ws'); ws.onmessage = (event) => { const data = JSON.parse(event.data); // 直接接收JSON数据 console.log(data); }; -
iframe + postMessage:
若需通过iframe加载跨域页面,可通过postMessage方法传递JSON数据。- 父页面:
const iframe = document.getElementById('child-iframe'); iframe.onload = () => { const data = { name: "王五", age: 25 }; iframe.contentWindow.postMessage(data, 'https://child-site.com'); };
- 父页面:



还没有评论,来说两句吧...