前端解决跨域问题

写在前边

前后端分离编码总是会遇到跨域问题,那么究竟应该如何解决呢?我们一起来探索一下吧。


什么是跨域?

广义的跨域

 - 资源跳转:a链接、重定向、表单提交等
 - 资源嵌入: 一些dom标签等
 - 脚本请求:js发起的ajax请求 dom和js对象的跨域操作等

然而我们平常所说的跨域是狭义上的,是由浏览器同源策略限制的一类请求场景

同源策略

1995年,同源政策有Netscape公司引入浏览器。目前所有浏览器都实行这个政策

所谓同源就是指:

  • 协议相同
  • 域名相同
  • 端口相同

举例来说:http://www.example.com/dir/page.html个网址中,协议是http://,域名是www.example.com,端口号是80*(默认)

http://www.example.com/dir2/other.html:同源
http://example.com/dir/other.html:不同源(域名不同)
http://v2.www.example.com/dir/other.html:不同源(域名不同)
http://www.example.com:81/dir/other.html:不同源(端口不同)

同源策略的目的,是为了保护用户信息的安全,防止恶意的网络切取数据。目前来说,如果非同源,有以下三种行为受到限制:

  1. cookie、ocalstorage、indexDB无法读取。
  2. DOM无法获得
  3. Ajax请求不能发送。

跨域解决方案

1.通过jsonp跨域
这种方法的基本思想就是,网页通过添加一个<script>元素,向服务器请求JSON数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。

//原生js
function addScriptTag(src) {
  var script = document.createElement('script'); //添加script元素
  script.setAttribute("type","text/javascript");
  script.src = src;
  document.body.appendChild(script);
}

window.onload = function () {
  addScriptTag('http://example.com/ip?callback=foo'); //注意callback
}

function foo(data) {
  console.log('Your public IP address is: ' + data.ip);
};

当服务器收到这个请求以后,会将数据放在回调函数的参数位置返回。


foo({
  "ip": "8.8.8.8"
})

当然jQuery Ajax也可以实现,直接上代码

$.ajax({
    url: 'http://example.com/ip',
    type: 'get',
    dataType: 'jsonp',  // 请求方式为jsonp
    jsonpCallback: "foo",    // 自定义回调函数名
    data: {}
});

jsonp 最大的特点就是简单适用,老式浏览器全部支持,服务器改造非常小。但是jsonp 只能实现get一种请求。

2.websocket协议跨域
websocket是html5的一种新协议,它实现了浏览器和服务器的全双工通信,同时允许跨域通信
来看一段实现代码

<div>
    user input:<input type="text">
</div>
<script src="./socket.io.js"></script>
<script>
var socket = io('http://www.domain2.com:8080');

// 连接成功处理
socket.on('connect', function() {
    // 监听服务端消息
    socket.on('message', function(msg) {
        console.log('data from server: ---> ' + msg); 
    });

    // 监听服务端关闭
    socket.on('disconnect', function() { 
        console.log('Server socket has closed.'); 
    });
});

document.getElementsByTagName('input')[0].onblur = function() {
    socket.send(this.value);
};
</script>

上面代码使用的是Socket.io,它很好的封装了websocket接口,提供了更简单灵活的接口,也对不支持websocket的浏览器提供了向下支持

3.跨域资源共享CORS

cors是一个w3c标准,全称是”跨域资源共享”(Cross-origin resource sharing)。它允许浏览器向跨源服务器发出XMLHttpRequest请求,从而客服了AJAX只能同源使用的限制。

普通跨域请求:只服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求:前后端都需要设置。
看下实现代码:

var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容

// 前端设置是否带cookie
xhr.withCredentials = true;

xhr.open('post', 'http://www.domain2.com:8080/login', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('user=admin');

xhr.onreadystatechange = function() {
    if (xhr.readyState == 4 && xhr.status == 200) {
        alert(xhr.responseText);
    }
};

jQuery实现

$.ajax({
    ...
   xhrFields: {
       withCredentials: true    // 前端设置是否带cookie
   },
   crossDomain: true,   // 会让请求头中包含跨域的额外信息,但不会含cookie
    ...
});

CORS与JSONP的使用目的相同,但是比JSONP更强大。
JSONP只支持GET请求,CORS支持所有类型的HTTP请求。JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。


以上就是我的一些理解
本文参考: https://segmentfault.com/a/1190000011145364
http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html
http://www.ruanyifeng.com/blog/2016/04/cors.html

猜你喜欢

转载自blog.csdn.net/liu0415111/article/details/79678665