JavaScript中跨域问题的深入理解
什么是跨域请求
在Web开发中,当a.com的JavaScript通过XMLHttpRequest发起对b.com的请求,此时在浏览器中会因为同源策略(Same-Origin Policy)而被阻止,这个错误就是跨域请求报错。同源策略是由浏览器同源策略规定的一个标准来限制页面脚本在不同域的文档/源中进行交互的安全机制。
当协议,域名或者端口号有任何一个不同的时候,我们都认为这是跨域请求。
常用结局跨域请求的方法
JSONP
JSONP (JSON with padding)是一种跨域请求的技术。JSONP并不是一种新的网络请求方式,而是一种网页在服务器上动态生成JSON数据的技术,在“JSON”和“Padding”二者的帮助下完成了在不同来源之间获取数据的任务。
- JSONP的原理
(1) 前端代码定义一个callback回调函数。
(2) 发起一个GET请求,并且请求的URL中包含callback回调函数的名称和随机数(防止缓存)。
(3) 服务器接受请求后,将数据打包成一个JSON对象,并将callback函数的名称和数据一起返回给前端(JavaScript)。
(4) 前端拿到响应结果后,会自动的调用callback回调函数,并将响应结果作为参数传入。
示例代码:
前端代码:
function handleResponse(data) {
console.log(data);
}
var script = document.createElement('script');
script.src = 'https://xxx.com/test?callback=handleResponse';
document.body.appendChild(script);
后端代码:
function test(request, response) {
// 拼接数据和callback函数名称
const res = JSON.stringify({ a: 1, b: 2 })
const callback = request.query.callback
response.end(callback + '(' + res + ')')
}
-
JSONP的缺点
-
只支持GET方法
- 存在安全风险(难以避免XSS攻击)
CORS
CORS(Cross-Origin Resource Sharing,跨源资源共享)是W3C标准,是目前最完善的解决跨域问题的方案。通过在Response header中添加一些验证信息,CORS可以在不需要前端或后端做任何特殊处理的情况下进行跨源请求,在安全和性能两方面都具有优势。
CORS可以使用以下方式验证:
- Origin:表示请求方的域名。
- Access-Control-Allow-Origin:表示允许这个域的哪些请求可以通过。
- Access-Control-Allow-Credentials:是否允许携带cookie,值为true或false
- Access-Control-Allow-Methods:表示允许这个域的哪些请求方法可以通过。例如:GET, POST, PATCH, PUT, DELETE。
- Access-Control-Allow-Headers:表示允许这个域的哪些请求头可以通过。例如:content-type,x-requested-with。
示例代码:
前端代码:
fetch('https://xxx.com/test', {
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
credentials: 'include'
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));
后端代码:
function test(request, response) {
// 设置允许接收跨域访问的源名称
response.setHeader('Access-Control-Allow-Origin', 'https://foo.com,https://bar.com');
// 允许跨域访问的http请求方法
response.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
response.setHeader('Access-Control-Allow-Credentials', true);
response.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type');
if (request.method === "OPTIONS") {
response.end();
return;
}
const res = JSON.stringify({ a: 1, b: 2 });
response.end(res);
}
代理请求
服务器端以后端接口调用为例,代码如下。具体思路:
- 前端通过jQuery、axios、fetch等库将请求发送给自己的服务器(本地服务器和接口服务器跨域)
- 后台接收到请求,再将请求转发给接口服务器
- 将接口服务器返回的数据原封不动的返回给前端。
优点:
不需要前端和后端进行配置,只需要后端对代理服务器进行设置。
缺点:
会增加代理层的成本和复杂度
示例代码:
前端代码:
fetch('https://xxx.com/api/test', {
method: 'GET',
headers: {
'Content-Type': 'application/json; charset=UTF-8',
},
})
.then(res => res.json())
.then(data => {
this.setState({
data: data,
});
})
.catch(error => {
console.log(error);
});
后端代码:
const proxyRequest = (req, res) => {
const targetUrl = "https://xxx.com";
// 此处应解析前端发送的请求数据并转发给对应的API接口
// 请求转发
const url = targetUrl + req.url;
const options = {
url: url,
method: req.method,
};
request(options, (err, response, body) => {
if (!err && response.statusCode === 200) {
const info = JSON.parse(body);
res.json(info || {});
} else {
res.sendStatus(500);
}
});
};
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JavaScript中跨域问题的深入理解 - Python技术站