首页 > 代码库 > 跨域请求解决方案
跨域请求解决方案
在前端开发过程中,难免和服务端产生数据交互。一般情况我们的请求分为这么几种情况:
- 只关注发送,不关注接收
- 不仅要发送,还要关注服务端返回的信息
- 同域请求
- 跨域请求
上面提到了一个概念,我们这里简单做一下讲解。什么叫做跨域?一般情况下,跨域分为三种情况:跨协议、跨子域、跨域名。下面距离梳理一下这三种情况。
- 跨协议:比如说我现在的域名地址是http://www.12306.cn,有一些请求需要发送到https://www.12306.cn,此时这个请求相对与http://www.12306.cn来说就是跨协议的请求
- 跨子域:比如说我现在是http://www.12306.cn,在登录的时候需要请求http://passport.12306.cn这个接口,此时这个请求就是跨子域的请求
- 跨域名:我们都知道现在的12306添加新的常用联系人的时候需要验证身份证号码,据说校验身份证号和姓名是否匹配只有公安部才有这个接口,并且使用费用相当高(扯远了),此时需要请求公安部的服务接口,此时从12306发出的请求就需要跨域名了
我们需要知道的是,跨域请求只要满足这是三种情况之一就会被认定为跨域请求。
目前流行比较广的跨域请求解决方案有:window.name、document.domain、服务端代理、jsonp、前端代理。
以下介绍的方式只是实现原理,没有过多考虑安全性,可以根据自己的情况进行选择。
- window.name
前端发送一个请求给隐藏的iframe,然后服务端每次将返回值,以js形式返回,然后iframe的父窗口获取window.name的值。服务端返回数据形式为:
<script>window.name={errno:0, errmsg:‘ok‘}</script>
- document.domain
这个使用限制条件较多,必须是不同子域间,协议和端口号必须相同。比如:a.12306.cn和b.12306.cn之间相互操作,可以分别在两个域名下定义:document.domain = ‘12306.cn‘; 这样就实现了跨子域通信。
- 服务端代理
这种情况不适合跨协议通信,比较适合跨端口和跨域名。这个前端基本上相当于普通的请求,我们所要访问的接口都经过服务端的代理,我们访问的请求都是本域的。
- jsonp请求
我们用的比较多,原理就是在发起请求时,动态的在页面加载一个script标签,因为src可以接收跨域资源,然后这个script标签的资源是执行一个js方法,并且将服务端返回的数据作为参数传递过来。这种情况唯一的缺点就是只能发送get请求,不适用用post请求。jsonp返回的数据格式为:
callback({errno:0,errmsg:‘ok‘});
- 前端代理
和window.name的实现比较类似,将请求发送到一个隐藏的iframe,然后服务端返回类似这样的内容:
<script>location.href=http://www.mamicode.com/‘http://www.12306.cn/proxy.html?func=callback&errno=0&errmsg=ok‘</script>>
然后proxy文件,接收到这些参数,进行处理,转化成类似与jsonp的返回值,执行页面上的回调。这种情况是可以发送post请求的。
proxy文件的内容,如下:
<!doctype html><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head><body><script type="text/javascript">(function(){ var queryStr = location.search.substring(1).split(‘&‘),oneQueryStr,args = {},g = parent,scope = parent ,callback; for(var i in queryStr){ oneQueryStr = queryStr[i].split(‘=‘); if(!callback && oneQueryStr[0] == ‘fun‘){ callback = oneQueryStr[1]; }; if(oneQueryStr[0]&&oneQueryStr[1]){ args[oneQueryStr[0]] = (oneQueryStr[1]||‘‘).replace(/[><‘"{}]/g, ‘‘); } } callback = callback.split(‘.‘); if( callback[0] === ‘document‘ || callback[0] === ‘location‘ || callback[0] === ‘alert‘){ }else{ for(var i = 0,len= callback.length;i<len;i++){ if(i==0 && callback[0]=="parent"){ g = parent; scope = parent; }else if(i==0 && callback[0]=="top"){ g = top; scope = top; }else{ if(i<len-1){ scope = scope[callback[i]]; } g = g[callback[i]]; } } g.call(scope,args); } })();</script></body></html>
通过上面的介绍,简单的知道了处理跨域请求的一些方法,下面整理了一个基于jquery的,解决跨域的方法。
$(function() { ‘use strict‘; /** * 交互类 * @param {object} param 要提交的数据 * @param {Object} [ajaxOpt] ajax配置 * @param {boolean} [https=false] 是否使用https协议 * @constructor */ var Sync = function(param, ajaxOpt, https) { var protocol = this.protocol = https ? ‘https‘: ‘http‘; var ajaxOptDefault = { url: protocol + ‘://‘+location.host, type: ‘GET‘, dataType: ‘jsonp‘, timeout: 20000 }; param = string2JSON(param) || {}; this.protocol = protocol; this.param = $.extend({}, param, ajaxOpt); this.ajaxOpt = $.extend({data: this.param}, ajaxOptDefault); this.HOST = protocol + ‘://‘+location.host; }; function string2JSON(str){ if($.isPlainObject(str)) { return str; } var params = {}; var str2Arr = str.split(‘&‘); $.each(str2Arr, function(i, keyVal) { var arr = keyVal.split(‘=‘); //去除serialize把空格转成+ params[arr[0]] = decodeURIComponent(arr[1]).replace(/[\+]+/, ‘‘).replace(/[\+]+/, ‘‘); }); return params; } $.extend(Sync.prototype, { /** * 通过get方式(jsonp)提交 * @param {String} [url] 请求链接 * @return {Object} promise对象 */ get: function(url) { var self = this; var send = $.ajax(url, this.ajaxOpt); return send.then(this.done, function(statues) { return self.fail(statues); }); }, /** * 通过post方式提交,依赖psp_jump.html文件 * @param {String} [url] 请求链接 * @return {Object} promise对象 */ post: function(url) { var deferred = $.Deferred(); var timer = null; var guid = parseInt(new Date().getTime().toString().substr(4), 10); var funName = ‘QBXJsonp‘ + guid; var formName = ‘QBXForm‘ + guid; var iframeName = ‘QBXIframe‘ + guid; // iframe 不能使用attr(‘name‘, xxx) 否则在ie7上添加的不是name属性而是submitName var iframe = $(‘<iframe name="‘ + iframeName +‘">‘).hide(); var param = $.extend({}, this.param, {proxy: this.HOST+‘/proxy.html‘, callback: funName}); var form = buildForm(param, {name: formName, target: iframeName, url: url || this.ajaxOpt.url}); window[funName] = function (data){ clearTimeout(timer); var value; for (var i in data) { if (data.hasOwnProperty(i)) { value = http://www.mamicode.com/decodeURIComponent(data[i]);>
这样我们就可以通过一下方式进行使用:
var login = function(data) { var sync = new Sync(data); return sync.post(sync.HOST+‘/login‘);} login({username: ‘blackMao‘, password: ‘blackMao‘}) .done(function() { alert(‘登陆成功!‘); }) .fail(function(error) { alert(error.errmsg); });
至此就可以做到跨域请求了~
跨域请求解决方案
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。