什么是跨域及解决办法
1. 跨域基础概念
1.1 什么是跨域
浏览器出于安全考虑,对不同源的请求进行限制,这就是同源策略。
1.2 同源策略要求
- 协议相同(http/https)
- 域名相同
- 端口相同
2. JSONP跨域方案
2.1 基本原理
- JSONP利用
<script>
标签不受同源策略限制的特性 - 通过函数调用的方式包装JSON数据
- 需要服务端配合返回特定格式的数据
2.2 实现示例
// 客户端实现
function jsonp(url, callback) {
const script = document.createElement('script');
script.src = `${url}?callback=${callback}`;
document.body.appendChild(script);
// 请求完成后删除script标签
script.onload = function() {
document.body.removeChild(script);
};
}
// 服务端实现(Python示例)
def jsonp_view(request):
callback = request.GET.get('callback')
data = {'name': 'test', 'value': 123}
return HttpResponse(f'{callback}({json.dumps(data)})')
2.3 JSONP限制
- 只支持GET请求
- 需要服务器配合
- 错误处理能力有限
3. CORS跨域方案
3.1 基本概念
CORS(Cross-Origin Resource Sharing)是W3C标准的跨域解决方案。
3.2 请求类型
简单请求
满足以下条件的请求:
-
请求方法:
- GET
- HEAD
- POST
-
允许的Header:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type (仅限):
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
非简单请求
- 不满足简单请求条件的请求
- 会触发预检请求(OPTIONS)
3.3 CORS配置
Django配置示例
# settings.py
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
# ... 其他中间件
]
# 允许所有域名访问
CORS_ALLOW_ALL_ORIGINS = True
# 或指定允许的域名
CORS_ALLOWED_ORIGINS = [
"https://example.com",
"https://api.example.com",
]
# 允许的请求方法
CORS_ALLOW_METHODS = [
'GET',
'POST',
'PUT',
'PATCH',
'DELETE',
'OPTIONS'
]
Flask配置示例
from flask_cors import CORS
app = Flask(__name__)
CORS(app, resources={
r"/api/*": {
"origins": "*",
"methods": ["GET", "POST", "PUT", "DELETE"],
"allow_headers": ["Content-Type"]
}
})
4. JSONP vs CORS 对比
4.1 功能对比
特性 | JSONP | CORS |
---|---|---|
请求方法 | 仅GET | 支持所有HTTP方法 |
客户端配置 | 需要 | 不需要 |
服务端配置 | 需要 | 需要 |
错误处理 | 有限 | 完善 |
标准化 | 非标准 | W3C标准 |
4.2 使用建议
- 优先使用CORS
- 需要兼容旧浏览器时使用JSONP
- 简单GET请求可以考虑JSONP
5. 安全考虑
5.1 CORS安全建议
- 不要使用
Access-Control-Allow-Origin: *
- 明确指定允许的域名
- 限制必要的HTTP方法
- 配置合适的缓存时间
5.2 最佳实践
- 使用HTTPS
- 实施适当的认证机制
- 验证请求来源
- 记录跨域请求日志