作为一个前端开发者,在工作中总是避免不了要涉及跨域问题,今天我们就来谈谈跨域。
什么是跨域?
浏览器从一个域名请求另一个域名的资源时,只要 协议、域名、端口 任何一处不同,便是跨域。
跨域产生的原因
跨域的产生和服务器代码什么的是无关的,它是由浏览器的同源策略导致的。
同源策略:
它是浏览器的一个安全策略,所有支持javascript的浏览器都遵循这个策略。为了用户安全着想,浏览器不允许不同协议、域名(包括子域名)、端口的地址之间进行访问。
解决跨域的方法
在实际开发中,我们避免不了要和非同源的服务器进行通讯,所以需要解决浏览器的非同源限制。从同源策略出发,要想解决跨域我们可以有以下几个方案。>
一:在浏览器设置禁止检查
通过设置--disable-web-security命令。
步骤:
①:下载并安装好chorme浏览器后在桌面找到浏览器快捷图标并点击鼠标右键的属性一栏。
②:在属性页面中的 目标 输入框里追加上 --disable-web-security 。
③:点击应用和确定后关闭属性页面,并打开chrome浏览器。如果浏览器出现提示“你使用的是不受支持的命令标记 --disable-web-security”,那么说明配置成功
注49版本后浏览器需另外设置,请自行百度。
- 此方法因为涉及到涉及操客户端作浏览器,在实际项目中肯定是不可行的我们不能去设置每个用户的浏览器,不过在日常开发中倒可以进行测试使用。
二:使用jsonp进行跨域请求
我们都知道直接在js中直接发起ajax跨域请求是不可能的,但是我们可以引入不同域下的js资源。jsonp就是利用了这一特点,通过动态的在页面建立script标签来实现跨域请求。(通过打算点方式可以看到在head中动态添加了一个script链接,src地址即所请求资源地址阿)
`
//创建标签(createElement)
var script = document.createElement("script");
//添加地址
script.src='http://test.adress.com?callback=callBackFun';
//添加给body的(成为body包涵的孩子)
document.head.appendChild(script);
//获取返回结果的回到函数
function callBackFun(res){
//res即获取的回调信息
console.log(JSON.stringify(res))
}
$.ajax({
url:'请求地址...',
type: 'GET',
dataType: 'jsonp',
//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback)
jsonp: 'callback',
//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名.
jsonpCallback: 'list',回掉函数名,默认jquery自动生成,指定jsonpCallback时可以将回掉函数写在ajax外面做其他操作,不指定时不能这样做,只能在success里做操作
success:function(json){
},
error:functon(res){
}
})
<!-- 当然的仅仅前台的这些代码是实现不了整个jsonp的跨域请求的,必须还要服务端进行修改,其中callback即是前后端约定的处理函数,此函数名必须和服务端方法名保持一致。 -->
`
- jsonp总结:
优点:不像ajax会受到浏览器的同源策略限制可以实现跨域,而且可以兼容非常古老的浏览器.
缺点:只支持get请求,不支持post、put、OPTIONS等其他http请求。
CORS实现跨域
CORS(Cross-Origin Resource Sharing)跨域资源共享,是一种机制,它使用额外的http请求头来让浏览器和服务器达成特殊约定,从而告诉浏览器哪些非同源服务器上的资源可以进行访问。另外CORS机制中对复杂请求会首先发起一个预请求,来确认服务端是否允许跨域。当服务端确认允许后,客户端才会发起一个实际真是的http请求,在预请求中,服务端也可以告诉客户端是否需要携带某身份验证。
CORS分为简单请求和非简单请求:
简单请求:
①:请求方式为get、post、head.
②:Content-Type仅为text/plain、multipart/form-data、application/x-www-form-urlencoded其中一种
- 对于简单请求,浏览器会直接发送CORS请求,在请求头里加入origin字段,在响应头里,会返回服务器设置的相关CORS字段,Access-Control-Allow-Origin字段对应的为允许跨域请求的源。若请求头里的源与服务器端设置源一致,服务器端检测通过,则允许跨域通讯。(在跨域的请求头报文里我们会看到多一个origin请求头)*
非简单请求:
①:使用了 put、delete、options、putch、trace、connect其中任一种http请求。
②:Content-Type不属于text/plain、multipart/form-data、application/x-www-form-urlencoded、中的任一种。
只要满足上面任一点即为非简单请求。
当发生非简单请求时,浏览器会首先发起一个预请求(options),来确认服务端是都允许该源进行跨域,当得到服务端确认允许后,客户端会发起一个真正的http请求,在预请求中,服务端也可以设置告诉客户端是否需要携带某种身份验证。
预检成功后,服务端响应的报文中将会展示支持的请求类型、支持的自定义首部及支持的跨域的源。
如图所示
其中
Access-Control-Allow-Origin: http://localhost:2015 允许跨域请求的源
Access-Control-Allow-Methods: post、get、delete、options 服务端支持的请求方式,注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次"预检"请求
Access-Control-Allow-Headers: x-request-with (服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段,多个用,分割)
Access-Control-Max-Ages: 3600 (预检请求可以被缓存的时间,单位秒,Firefox中最大24小时,Chromium中10分钟,-1表示禁止缓存,即每一次请求都要发送预请求)
一旦浏览器通过了预检请求,以后每次浏览器正常的CORS请求和简单请求一样,会有一个origin头部信息字段,响应报文里也有一个Access-Control-Allow-Origin响应头信息字段。
使用CORS实现跨域,主要需要服务端进行配置,前端无需做大修改(或者前端可以通过nginx、apach进行代理配置),不过如果携带cookie信息时,前端需要配置withCredentials为ture.此时服务端Access-Control-Allow-Origin也不能简单的设置为“*”,而是要设置成具体的请求源地址。需要进行动态配置。
CORS总结:
优点:配置方便,便于操作、可以实现任何类型的http请求。
缺点:不兼容低版本浏览器。
总结
总体来说,在实际开发中,我们都会用jsonp和CORS进行跨域请求,两者各有优劣,根据需求大家合理利用,另外在本文中如有不恰当之处,欢迎纠正!