JSON 跨域数据设置:从原理到实践全解析
在前后端分离的开发架构中,JSON 凭借其轻量、易读的特性,已成为前后端数据交互的核心格式,由于浏览器的同源策略(Same-Origin Policy)限制,当页面与请求数据的源(协议、域名、端口任一不同)不一致时,跨域请求会被浏览器拦截,导致 JSON 数据无法正常获取,本文将解析 JSON 跨域数据的设置原理,并介绍多种实用的跨域解决方案。
跨域问题的根源:同源策略
同源策略是浏览器的一种核心安全机制,它限制了一个文档(或脚本)如何从另一个源加载资源,这里的“源”由协议(http/https)、域名(如 example.com)、端口(如 80/443)共同决定。
https://www.example.com:8080/api/data与https://api.example.com:8080/api/data(域名不同)http://example.com与https://example.com(协议不同)http://example.com:80`` 与http://example.com:8080`(端口不同)
组合均属于不同源,浏览器会直接阻止跨域请求,并在控制台报错类似:Access-Control-Allow-Origin 不允许的错误。
JSON 跨域数据的核心解决方案
CORS(跨域资源共享):官方推荐的标准方案
CORS(Cross-Origin Resource Sharing)是 W3C 制定的跨域资源访问标准,通过服务器在 HTTP 响应头中添加特定字段,明确告知浏览器“允许哪些源访问该资源”,从而绕过同源策略限制,这是目前最主流、最规范的跨域解决方案。
(1)CORS 的核心响应头
服务器需在 HTTP 响应中添加以下关键头信息:
Access-Control-Allow-Origin:必须设置,指定允许访问的源。- 单个源:
Access-Control-Allow-Origin: https://www.frontend.com - 所有源:
Access-Control-Allow-Origin: *(生产环境需谨慎,避免安全风险)
- 单个源:
Access-Control-Allow-Methods:必须设置,允许的 HTTP 方法(如 GET、POST、PUT、DELETE)。
示例:Access-Control-Allow-Methods: GET, POST, OPTIONSAccess-Control-Allow-Headers:必须设置,允许的请求头(如 Content-Type、Authorization)。
示例:Access-Control-Allow-Headers: Content-Type, X-Custom-HeaderAccess-Control-Allow-Credentials:可选,是否允许发送 Cookie 或 HTTP 认证信息。
若需携带 Cookie,需设置为true,且Access-Control-Allow-Origin不能为 (必须明确指定源)。
示例:Access-Control-Allow-Credentials: trueAccess-Control-Max-Age:可选,预检请求(OPTIONS)的有效期(秒),减少重复预检请求。
示例:Access-Control-Max-Age: 3600
(2)CORS 的两种请求类型
-
简单请求(Simple Request):满足以下条件的请求:
- 方法:GET、POST、HEAD
- 头信息:仅限
Accept、Accept-Language、Content-Language、Content-Type(且值为application/x-www-form-urlencoded、multipart/form-data、text/plain) - 请求体:无自定义字段
简单请求会直接发送,服务器通过响应头
Access-Control-Allow-Origin等字段判断是否允许跨域。 -
预检请求(Preflight Request):不满足简单请求条件的请求(如方法为 PUT/DELETE、请求头包含
Authorization、请求体为 JSON)。
浏览器会先发送一个OPTIONS方法请求到服务器,询问是否允许后续的实际请求,服务器需响应200并返回Access-Control-Allow-Methods、Access-Control-Allow-Headers等字段,浏览器收到确认后才会发送实际请求。
(3)服务器端实现示例
以 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, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
next();
});
// 处理预检请求
app.options('*', (req, res) => {
res.sendStatus(200);
});
// 模拟返回 JSON 数据
app.get('/api/data', (req, res) => {
res.json({
code: 200,
message: '跨域数据获取成功',
data: { id: 1, name: 'JSON 跨域示例' }
});
});
app.listen(3000, () => {
console.log('服务器运行在 http://localhost:3000');
});
若需携带 Cookie,需调整 Access-Control-Allow-Origin 并启用 credentials:
// 允许特定源且携带 Cookie
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', 'https://www.frontend.com');
res.header('Access-Control-Allow-Methods', 'GET, POST');
res.header('Access-Control-Allow-Headers', 'Content-Type');
res.header('Access-Control-Allow-Credentials', 'true'); // 允许携带 Cookie
next();
});
JSONP(JSON with Padding):仅支持 GET 的兼容方案
JSONP 是一种早期的跨域解决方案,利用 <script> 标签的跨域能力(不受同源策略限制)实现数据交互,但 JSONP 仅支持 GET 请求,且存在安全风险(如 XSS 攻击),目前已逐渐被 CORS 替代,仅在部分老旧项目中使用。
(1)JSONP 的原理
前端通过动态创建 <script> 标签,将请求 URL 后拼接回调函数名(如 callback=handleResponse);服务器收到请求后,返回一段 JavaScript 代码,调用该回调函数并传入 JSON 数据(如 handleResponse({"code": 200, "data": {...}}));前端执行这段代码,回调函数被触发,数据得以处理。
(2)JSONP 实现示例
前端代码(HTML):
<script>
function handleResponse(data) {
console.log('获取到的 JSON 数据:', data);
document.getElementById('result').innerText = JSON.stringify(data);
}
// 动态创建 script 标签
function fetchJsonpData() {
const script = document.createElement('script');
script.src = 'https://api.example.com/jsonp?callback=handleResponse';
document.body.appendChild(script);
}
</script>
<button onclick="fetchJsonpData()">获取 JSONP 数据</button>
<div id="result"></div>
服务器端代码(Node.js):
app.get('/jsonp', (req, res) => {
const callback = req.query.callback; // 获取回调函数名
const data = { code: 200, message: 'JSONP 数据', data: { id: 1 } };
const jsonpStr = `${callback}(${JSON.stringify(data)})`; // 拼接回调函数调用
res.send(jsonpStr);
});
代理服务器:前后端均可实现的绕行方案
当无法直接修改服务器 CORS 配置时,可通过代理服务器转发请求,将跨域请求转换为同源请求,代理服务器可以是前端开发服务器(如 Vite、Webpack DevServer)或后端中间件。
(1)前端开发服务器代理(以 Vite 为例)
在 vite.config.js 中配置代理:
import { defineConfig } from 'vite';
export default defineConfig({
server: {
proxy: {
'/api': { // 请求路径以 /api 开头时触发代理
target: 'https://api.example.com', // 目标服务器地址
changeOrigin: true, // 修改请求头中的 Origin 为目标地址
rewrite: (path) => path.replace(/^\/api/, '') // 可选:重写请求路径
}
}
}
});
前端请求时,直接写相对路径:
// 浏览器实际请求:https://api.example.com/data
fetch('/api/data').then(res => res.json()).then(console.log);
(2)Nginx 反向代理
生产环境中,可通过 Nginx 配置代理:
server {
listen 80;
server_name www.frontend.com;
# 前端静态文件
location / {
root /var/www/frontend;
try_files $uri $uri/ /index.html;
}
# 代理 API 请求
location /api/ {
proxy_pass https://api.example.com/; # 目标服务器


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