关于浏览器的跨域问题
浏览器请求机制与AJAX
Web的运作原理:一次HTTP请求对应一个页面。也就是每次http请求后页面会跳转或者刷新。
然而这样明显是很麻烦的,我们需要在同一个页面内多次请求数据,于是我们就需要AJAX(Asynchronous Javascript and XML)。
AJAX可以让页面发出新的http请求,取得数据后再更新页面内数据,就相当于停留在了当前页面。
而AJAX最重要的就是Asynchronous(async),也就是异步,异步回调也是js的一个语言特征,ajax异步执行后用js回调来获得响应十分方便。
若不使用JQuery,而是使用原生js编写的话,我们需要用到XMLHttpRequest对象:
var request = new XMLHttpRequest(); // 新建对象
request.onreadystatechange = function(){ // 状态改变时进行回调
if(request.readyState === 4){
if(request.status === 200){
// 成功
}
else{
// 失败
}
}
else{
// http请求没有结束
}
}
const url = '/api/data'
request.open('GET',url); // open函数三个参数,第一个是方法GET或POST,第二个是url地址,第三个是否使用异步,默认为true,一般也不要修改成false
request.send(); // 当方法为post时,需要将数据作为参数传入
但是低版本IE不支持XMLHttpRequest对象,而是使用ActiveXObject对象:
var request = new ActiveXObject('Microsoft.XMLHTTP'); // 只要将这句赋值语句换掉即可
又或者先行判断,扩展代码的兼容性:
var request;
if(window.XMLHttpRequest){
request = new XMLHttpRequest();
}
else{
request = new ActiveXObject('Microsoft.XMLHTTP');
}
关于浏览器请求的安全限制
上述实例代码中url使用相对路径,如果使用外域链接时会出现报错。这个也称作浏览器的同源策略。
如何判断同源或者说是在同一个域内呢?处于同一个域内需要满足以下三个条件:
域名相同(www.example.com与example.com不同)、协议(http与https不同)相同、端口号(localhost:8080和localhost:80不同)相同。
如何跨域传输数据
但是在实际应用中我们总是需要请求外域链接数据的,我们有以下几种方法可以做到:
-
通过Flash插件发送HTTP请求
但是需要安装flash并且现在flash并不流行了(与其说不流行不如说是要被淘汰了,chrome都不支持了。。。)
-
在同源域名下假设一个代理服务器来转发请求(proxy)
需要再搭建一个代理服务器,也相当麻烦。
-
JSONP
实际上是利用了浏览器允许跨域引用JavaScript的资源,也就是返回一个带数据的js函数,然后我们本地编写好一个回调函数即可。
再到代码里理解就是因为script标签没有不受同源限制,因此只要我们动态的创建一个script标签并将url赋予到src属性中,我们就可以做到跨域请求。
但是jsonp有个限制:只能使用GET请求方式。
准备回调函数:
function refreshPrice(data){ // 回调函数的函数名要与返回来的函数名相同 var p = document.getElementById('test-jsonp'); p.innerHTML = '当前价格:' + data['0000001'].name +': ' + data['0000001'].price + ';' + data['1399001'].name + ': ' + data['1399001'].price; // 这里随便举了个例子,按照外部api文档来设置好数据 }
而我们还需要将外部url作为参数传到html文件里head标签下的script标签src属性中。
function getPrice() { var js = document.createElement('script'); // 动态创建script标签 head = document.getElementsByTagName('head')[0]; js.src = 'http://api.money.126.net/data/feed/0000001,1399001?callback=refreshPrice'; // 廖雪峰老师教程中提供的api,callback=后面的就是返回的函数名 head.appendChild(js); }
在一些实际应用中,github上有许多封装好的jsonp库,我们也可以选择直接调用而不需要手写。
-
CORS
浏览器支持html5我们就可以使用cors来进行跨域访问了。
CORS(Cross-Origin Resource Sharing),是HTML5规范定义的如何跨域访问资源。 Origin表示本域,也就是浏览器当前页面的域。而是否能够成功请求取决于对方服务器给予的响应头部(Header)中Access-Control-Allow-Origin的值,如果该值为*或者你当前浏览器所在域名,就可以成功请求资源,否则请求会被拒绝。
除此以外,服务器设置中也会有另外一个参数Access-Control-Allow-Methods用以规定请求使用的方法可以有哪些。
同时还有诸如Access-Control-Max-Age之类的参数,深入了解HTTP协议的话就会了解得到,这里不作过多叙述。
除了常见的PUT,DELETE,GET,POST请求方法以外,还有一个方法是OPTION,这个方法一般用于发送ajax请求前将请求的host,origin,method发到服务器端,一般服务器应该要对此做出响应,返回的参数就会有上述提到的Access-Control-Allow-Origin、Access-Control-Allow-Methods等,此时浏览器对于返回参数进行确认自己的请求符合条件后就会发送真正的请求,否则浏览器这一端就会自己拦截下来。
总结
跨域问题是在前后端交互中必然会遇到的问题,引用外部域资源的情况很常见,所以必须搞清楚这里底层的交互原理,最好可以深入的再研读一下HTTP协议。 深入了解CORS也可以阅读W3C文档。