本文将从多个方面对前端解决跨域问题的8种方案(最新最全)进行详细的阐述。
一、JSONP跨域方案
JSONP(JSON with Padding)是一种跨域请求方案。它通过动态创建<script>标签,向服务器发起请求,服务器返回指定函数调用的数据,实现数据获取。
首先,定义一个处理数据的函数,将该函数名传递给服务器端:
function handleData(data){
console.log(data); // 处理数据
}
<script src="http://www.example.com/data.php?callback=handleData"></script>
服务器返回的数据格式如下:
handleData({"id":1,"name":"jack"});
优点:对于低版本的浏览器,JSONP方案是最可行的解决方案。
缺点:对于非GET请求,不能使用JSONP解决跨域问题。另外,JSONP获取的数据只能是JSON格式的。
二、CORS跨域方案
跨域资源共享(CORS,Cross-Origin Resource Sharing)标准允许像其他域发送XMLHttpRequest请求。该标准需要浏览器和服务器都支持。浏览器会在请求头中携带一个Origin字段来告诉服务器请求的来源,服务器通过在响应头中设置Access-Control-Allow-Origin字段来允许或禁止请求。
在前端可以通过设置XMLHttpRequest的withCredentials属性来携带跨域的凭据(cookie等)。在服务器端,需要设置Access-Control-Allow-Credentials字段为true才能接受跨域的凭据。
代码示例:
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
console.log(xhr.responseText);
}
}
xhr.open('POST', 'http://www.example.com');
xhr.send();
对应服务器端的代码:
header("Access-Control-Allow-Origin: http://www.example.com");
header("Access-Control-Allow-Credentials: true");
优点:使用简单,支持所有类型的HTTP请求,请求与响应的信息更丰富。
缺点:比较麻烦,需要在服务器端设置。另外,IE10以下的浏览器不支持CORS。
三、WebSocket跨域方案
WebSocket是HTML5中新增的一种网络通信协议。因为它能在浏览器与服务器之间建立持久性的连接,使用它进行通信相对于HTTP请求来说更加灵活和高效。
WebSocket跨域通信同样需要跨域的服务器端支持。如果浏览器与服务器端都支持WebSocket,那么就可以在JavaScript代码中直接使用WebSocket API建立连接。
代码示例:
var ws = new WebSocket('ws://www.example.com/server');
ws.onopen = function(){
ws.send('Hello Server!');
}
ws.onmessage = function(event){
console.log(event.data);
}
优点:支持双向通信,速度快,消息实时性强。
缺点:需要浏览器与服务器端都支持WebSocket,需要跨域的服务器端支持。
四、代理跨域方案
代理跨域方案指的是,前端将请求发送给本地服务器,后端的本地服务器将请求发送给目标服务器,接收到响应后再将响应返回前端。
代码示例:
var proxyUrl = 'http://www.example.com/proxy';
var targetUrl = 'http://www.target.com';
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
console.log(xhr.responseText);
}
}
xhr.open('GET', proxyUrl + '?url=' + encodeURIComponent(targetUrl));
xhr.send();
对应本地服务器的代码:
var request = require('request');
var express = require('express');
var app = express();
app.get('/proxy', function(req, res){
var url = req.query.url;
request(url, function(error, response, body){
if(!error && response.statusCode === 200){
res.setHeader('Content-Type', 'application/json;charset=utf-8');
res.send(body);
}
});
});
app.listen(3000, function(){
console.log('Proxy server is running at port 3000.');
});
优点:容易实现,适用于各种类型的HTTP请求,支持跨域访问所有资源。
缺点:不适用于大量并发请求,需要自己搭建代理服务器。
五、Nginx反向代理跨域方案
Nginx是一款高性能的Web服务器和反向代理服务器。通过设置Nginx服务器作为前端浏览器与目标服务器之间的代理服务器,将所有的请求和响应都转发到Nginx上,再由Nginx将请求转发给目标服务器,实现跨域请求。
代码示例:
server {
listen 80;
server_name www.example.com;
location / {
proxy_pass http://www.target.com;
add_header Access-Control-Allow-Origin *;
}
}
优点:适用于大量并发请求,易于配置,在服务端实现跨域。
缺点:需要一定的服务器管理经验,适用于HTTP请求。
六、postMessage跨域方案
HTML5中的postMessage允许跨窗口通信,可用于在两个不同域之间传递数据,从而实现跨域通信。
代码示例:
// 在iframe所在的页面中
var targetOrigin = "http://www.example.com";
window.onload = function(){
var iframeWin = document.getElementById("iframe").contentWindow;
iframeWin.postMessage("hello",targetOrigin);
}
// 在被嵌套的iframe页面中
window.onmessage = function(event){
if(event.origin === 'http://www.target.com'){
console.log(event.data); // "hello"
event.source.postMessage("world", "http://www.example.com");
}
}
优点:可方便地在两个不同域之间进行跨域通信。
缺点:由于postMessage自身的特性,接收方需要能够知道消息的来源,存在一定的安全问题。
七、document.domain跨域方案
document.domain方案只适用于主域名相同,子域名不同的跨域访问场景。通过将两个彼此通信的页面的document.domain都设置为相同的主域名,就可以实现页面之间的跨域访问。
代码示例:假设两个跨域的页面为"http://www.a.example.com/"和"http://www.b.example.com/",则可以在这两个页面中添加如下代码:
// 在a.example.com中设置
document.domain = 'example.com';
// 在b.example.com中设置
document.domain = 'example.com';
优点:简单易用,不需要修改服务器端的配置。
缺点:只适用于主域名相同,子域名不同的场景。
八、跨域资源嵌入跨域方案
在跨域资源嵌入跨域方案中,前端将目标地址嵌入页面中,请求嵌入的地址时使用script标签、link标签等形式进行,服务器端返回的数据会被嵌入到页面中进行执行。在返回结果时,如果成功,则可以利用回调函数或者状态码的方式将结果传递给前端代码。
代码示例:
// 使用script标签请求跨域嵌入资源
<script src="http://www.target.com/resource?callback=handleData"></script>
function handleData(data){
console.log(data);
}
对应目标服务器端的代码:
$callback = $_GET["callback"];
$data = array("id"=>1, "name"=>"jack");
header("Content-Type:application/json;charset=utf-8");
echo $callback.'('.json_encode($data).')';
优点:简单易用,适用于各种类型的HTTP请求。
缺点:需要进行字符串处理,存在一定的安全风险。