Web 跨域请求
在前端开发过程中,难免和服务端产生数据交互。一般情况我们的请求分为这么几种情况:
1. 只关注发送,不关注接收
2.不仅要发送,还要关注服务端返回的信息
a. 同域请求
b. 跨域请求
所谓 跨域,一般情况下为三种情况:跨协议、跨子域、跨域名。下面距离梳理一下这三种情况。
跨协议:比如说我现在的域名地址是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.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 = decodeURIComponent(data[i]);
if (value.match(/^(\{.*\})|(\[.*\])$/)) {
value = $.parseJSON(value);
}
data[i] = value;
}
}
deferred.resolve(data);
};
timer = setTimeout(function(){
deferred.reject({
errno: 999999,
errmsg: '网络超时,请稍后重试'
});
}, this.ajaxOpt.timeout);
// do some clear
deferred.always(function(data) {
$(iframe).remove();
$(form).remove();
// IE8以下不支持delete window属性
try {
delete window[funName];
} catch (e){
window[funName] = null;
}
});
$(document.body).append(iframe).append(form);
$(form).submit();
return deferred.then(this.done);
},
/**
* 收到响应时默认回调
* @param {Object} data 数据
* @return {Object}
*/
done: function (data) {
var deferred = $.Deferred();
if (data.errno == 0) {
deferred.resolve(data);
} else {
deferred.reject(data);
}
return deferred.promise();
},
/**
* 未收到响应时默认回调
* @param {Object} error 错误信息
* @return {Object}
*/
fail: function(error) {
var deferred = $.Deferred();
deferred.reject({
errno: 999999,
errmsg: '网络超时,请稍后重试'
});
return deferred.promise();
}
});
/**
* 把数据对象转成form元素
* @param {Object} data json数据
* @param {Object} opts form所需参数或其他数据
* @return {Object}
*/
function buildForm(data, opts) {
if (opts.url) {
opts.action = opts.url;
delete opts.url;
}
opts.method = 'post';
var $form = $('<form>').attr(opts).hide();
$.each(data, function (name, value) {
$('<input>').attr({type: 'hidden', name: name, value: value}).appendTo($form);
});
return $form[0];
}
window.Sync = Sync;
});
这样我们就可以通过一下方式进行使用:
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);
});
至此就可以做到跨域请求了
Web 跨域请求的更多相关文章
- Web 跨域请求问题的解决方案- CORS 方案
1.什么是跨域 跨域是指跨域名的访问,以下情况都属于跨域: 跨域现象 实例 域名不相同 www.baidu.com与www.taobao 一级域名相同,但是端口不相同 www.baidu.com:80 ...
- web跨域请求
第一种情况: 1. sina.com=====>baidu.com/xxx.jsp 也就是前面的域名不相同,(url第三根斜杠之前的内容,也就是主机) 2:localhost =====> ...
- Web 跨域请求(OCRS) 前端解决方案
1.同源策略如下: URL 说明 是否允许通信 http://www.a.com/a.jshttp://www.a.com/b.js 同一域名下 允许 http://www.a.com/lab/a.j ...
- 基于.Net Framework 4.0 Web API开发(5):ASP.NET Web APIs AJAX 跨域请求解决办法(CORS实现)
概述: ASP.NET Web API 的好用使用过的都知道,没有复杂的配置文件,一个简单的ApiController加上需要的Action就能工作.但是在使用API的时候总会遇到跨域请求的问题,特 ...
- javascript跨域请求RESTful Web Service
跨域请求RESTful Web Service 当我们用js请求RESTful Web Service的时候,通常会出现跨域无法访问的问题,也就是无法正常得到我们要的值.jsonp是个解决问题的方法. ...
- Java Web解决跨域请求
要知道跨域请求就要先了解同源策略,那么什么是同源?什么是不同源?简单来说就是,如果两个资源,包括HTML页面.JavaScript脚本.css样式,对应的协议.域名和端口完全相同,那么这两个资源就是同 ...
- Spring Boot Web应用开发 CORS 跨域请求支持:
Spring Boot Web应用开发 CORS 跨域请求支持: 一.Web开发经常会遇到跨域问题,解决方案有:jsonp,iframe,CORS等等CORS与JSONP相比 1. JSONP只能实现 ...
- Java Web应用中支持跨域请求
转载:https://blog.csdn.net/lmy86263/article/details/51724221 由于工程合作开发的需要,后台的应用要能支持跨域访问,但是在这个跨域访问“时好时坏” ...
- ASP.NET web api 跨域请求
1.学习文章:AJAX 跨域请求 - JSONP获取JSON数据 1.asp.net代码 参考文章:http://www.sxt.cn/info-2790-u-756.html (1).增加CorsH ...
随机推荐
- ftp添加虚拟用户的实例
本文主要讲解添加一个ftp虚拟用户的流程,接上文 https://www.cnblogs.com/tssc/p/9582780.html ========= 完美的分割线 ======== 1.修改授 ...
- STM32 用c语言控制4个LED灯从左向右无限流动
在用c语言写LED流水灯的前提条件是配置好其他环境,这里我就不说环境了, 想让LED灯无限循环时,首先要想到的是无限循环函数,我这里利用的是for函数 无限循环. #include "stm ...
- vue 钩子
生命周期总结 这么多钩子函数,我们怎么用呢,我想大家可能有这样的疑问吧,我也有,哈哈哈. beforecreate : 举个栗子:可以在这加个loading事件 created :在这结束loadin ...
- (1)什么是socket(套接字)
什么是套接字socket socket把传输层以下的协议都封装成了简单的接口,我编写基于网络通信的软件只需要调用这些接口即可,写出的程序自然是遵循tcp/udp协议的.... 什么是互联网 互联网=物 ...
- C4D 计算体积和表面积插件
前段时间,由于有个模型要做3D打印,所以需要知道模型的体积以及表面积,以便计算价格. 我用的是C4D,恕我愚昧,在C4D上没找到自带的. 在网上找了好久,才找到一个由法国开发名为aire_volume ...
- POJ2155 Matrix
分析 好博客 区间修改,单点查询的题,可以用经典的树状数组的转化,把它化为单点修改,区间查询. 方法是在一些点上加1,最后查询单点的前缀和模2即为答案.相当于维护的是一个异或差分,利用了容斥. 可对查 ...
- LG1801 【黑匣子_NOI导刊2010提高(06)】
看到各路dalao用平衡树的做法,表示本人不才,并不会. 然而我会优先队列_huaji_,并且发现用堆解题的dalao们并没有基于在线的做法 于是我的showtime到了 评测结果:https://w ...
- 一个不错的nomad raw_exec && docker 运行例子(集成访问网关)
github 上有一个关于nomad up && runing 不错的项目,包含了一个tomcat 应用的部署,以及基于容器运行的网关服务 项目参考地址 https://github. ...
- Cocos2D-X2.2.3学习笔记13(延时动作)
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/q269399361/article/details/28265477 还记得我们上一节讲的瞬时动作吗 ...
- oracle归档日志配置查询
归档日志(Archive Log)是非活动的重做日志备份.通过使用归档日志,可以保留所有重做历史记录,当数据库处于ARCHIVELOG模式并进行日志切换式,后台进程ARCH会将重做日志的内容保存到归档 ...