接口返回JSON实现跨域的完整指南:从原理到实践
在前后端分离的开发模式中,跨域(Cross-Origin Resource Sharing, CORS)是一个绕不开的问题,当前端页面与后端接口的协议、域名或端口三者之一存在差异时,浏览器出于安全考虑会阻止跨域请求,导致接口无法正常获取JSON数据,本文将从跨域的底层原理出发,详细介绍接口返回JSON时实现跨域的多种方案,并附上具体代码示例,帮助开发者彻底解决跨域问题。
什么是跨域?为什么需要处理跨域?
跨域的本质是浏览器的同源策略(Same-Origin Policy)的限制,同源策略要求:如果两个页面的协议(http/https)、域名(如a.com/b.com)、端口(如80/8080)完全相同,则它们属于同源,可以互相访问资源;否则,就属于跨域,浏览器会阻止跨域请求(如AJAX、Fetch)。
- 前端页面:
https://www.frontend.com(协议:https,域名:www.frontend.com,端口:443) - 后端接口:
http://api.backend.com/data(协议:http,域名:api.backend.com,端口:80)
前端页面请求后端接口属于跨域,浏览器会直接拦截请求,即使后端返回了JSON数据,前端也无法接收。
跨域的核心解决方案:CORS机制
跨域的主流解决方案是CORS(跨域资源共享),CORS通过HTTP头信息,允许服务器声明哪些外部源可以访问资源,从而在保证安全的前提下实现跨域。
CORS的工作原理
CORS的核心是服务器响应头,当浏览器发起跨域请求时,会自动在请求头中添加Origin字段(标识请求来源),服务器根据Origin判断是否允许跨域,并通过响应头告诉浏览器是否允许该请求。
关键响应头包括:
Access-Control-Allow-Origin:允许跨域的源(如https://www.frontend.com或表示所有源)。Access-Control-Allow-Methods:允许的请求方法(如GET、POST、PUT、DELETE)。Access-Control-Allow-Headers:允许的请求头(如Content-Type、Authorization)。Access-Control-Allow-Credentials:是否允许携带凭证(如Cookie、Authorization头)。Access-Control-Max-Age:预检请求的缓存时间(减少重复预检请求)。
CORS的请求类型
根据请求方式的不同,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等响应头决定是否允许。
- 请求方法:
-
非简单请求(Non-Simple Request):不满足简单请求条件的请求(如请求方法为
PUT/DELETE,或请求头为application/json,或携带自定义头),非简单请求会先发送一个预检请求(OPTIONS),询问服务器是否允许实际请求,服务器返回200 OK并携带CORS响应头后,浏览器才会发送实际请求。
后端接口实现跨域的具体方案
无论是哪种后端语言(如Java、Python、Node.js、PHP),实现跨域的核心都是设置正确的CORS响应头,以下是常见后端语言的实现示例。
Node.js(Express框架)
Express是Node.js的常用框架,可以通过cors中间件或手动设置响应头实现跨域。
方案1:使用cors中间件(推荐)
const express = require('express');
const cors = require('cors'); // 安装:npm install cors
const app = express();
// 允许所有源跨域(开发环境)
app.use(cors());
// 允许特定源跨域(生产环境)
// app.use(cors({
// origin: 'https://www.frontend.com',
// methods: ['GET', 'POST'],
// allowedHeaders: ['Content-Type', 'Authorization'],
// credentials: true // 允许携带Cookie
// }));
// 接口返回JSON
app.get('/api/data', (req, res) => {
res.json({
code: 200,
message: 'success',
data: { name: '跨域测试', age: 18 }
});
});
app.listen(3000, () => {
console.log('Server is running on http://localhost:3000');
});
方案2:手动设置响应头
const express = require('express');
const app = express();
app.get('/api/data', (req, res) => {
// 设置允许跨域的源(*表示所有源,生产环境建议指定具体源)
res.setHeader('Access-Control-Allow-Origin', '*');
// 允许的请求方法
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
// 允许的请求头
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
// 允许携带凭证(如Cookie)
res.setHeader('Access-Control-Allow-Credentials', 'true');
res.json({
code: 200,
message: 'success',
data: { name: '手动设置跨域', age: 18 }
});
});
Java(Spring Boot框架)
Spring Boot提供了@CrossOrigin注解,可以快速为接口或Controller添加跨域支持。
方案1:使用@CrossOrigin注解(推荐)
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DataController {
// 为单个接口添加跨域支持
@GetMapping("/api/data")
@CrossOrigin(origins = "https://www.frontend.com") // 允许的源
public Object getData() {
return new Result(200, "success", new Data("跨域测试", 18));
}
// 为整个Controller添加跨域支持
@CrossOrigin(origins = "*", allowedHeaders = "*") // 允许所有源(开发环境)
@RestController
public class DataController2 {
@GetMapping("/api/data2")
public Object getData2() {
return new Result(200, "success", new Data("Controller级跨域", 20));
}
}
}
// 封装返回结果
class Result {
private int code;
private String message;
private Object data;
public Result(int code, String message, Object data) {
this.code = code;
this.message = message;
this.data = data;
}
// 省略getter和setter
}
class Data {
private String name;
private int age;
public Data(String name, int age) {
this.name = name;
this.age = age;
}
// 省略getter和setter
}
方案2:通过全局配置实现跨域
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 对所有接口生效
.allowedOrigins("https://www.frontend.com") // 允许的源
.allowedMethods("GET", "POST", "PUT", "DELETE") // 允许的请求方法
.allowedHeaders("*") // 允许所有请求头
.allowCredentials(true) // 允许携带凭证
.maxAge(3600); // 预检请求缓存1小时
}
}
Python(Django框架)
Django实现跨域的方式有多种,如使用django-cors-headers库或手动设置响应头。
方案1:使用django-cors-headers库(推荐)
# 安装:pip install django-cors-headers
# settings.py
INSTALLED_APPS = [
# ...
'corsheaders', # 添加到INSTALLED_APPS
# ...
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware', # 添加到MIDDLEWARE顶部(优先级高)
'django.middleware.security.SecurityMiddleware',
# ...
]
# 跨域配置
CORS_ALLOW_ALL_ORIGINS = True # 允许所有源(开发环境)
# 生产环境建议指定具体源:
# CORS_ALLOWED_ORIGINS = [
# "https://www.frontend.com",
# "http://localhost:3000", # 开发环境


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