怎么解决服务器间的js解决跨域问题题

js 跨域访问问题解决方法_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
js 跨域访问问题解决方法
上传于||文档简介
&&什​么​引​起​了​a​j​a​x​不​能​跨​域​请​求​的​问​题​?​
​
​a​j​a​x​本​身​实​际​上​是​通​过​X​M​L​H​t​t​p​R​e​q​u​e​s​t​对​象​来​进​行​数​据​的​交​互​,​而​浏​览​器​出​于​安​全​考​虑​,​不​允​许​j​s​代​码​进​行​跨​域​操​作​,​所​以​会​警​告​。​
​
​
​
​有​什​么​完​美​的​解​决​方​案​么​?​ ​
​
​解​决​方​案​有​不​少​,​但​是​只​能​是​根​据​自​己​的​实​际​情​况​来​选​择​。​
​
​
​
​跨​域​的​安​全​限​制​都​是​指​浏​览​器​端​来​说​的​,​服​务​器​端​是​不​存​在​跨​域​安​全​限​制​的​。​所​以​衍​生​出类​跨​域​解​决​方​案​,​一​类​是​服​务​器​端​做​中​转​类​似​代​理​方​式​,​一​类​是​j​s​处​理​浏​览​器​端​的​真​正​跨​域​访​问​。
阅读已结束,如果下载本文需要使用1下载券
想免费下载本文?
下载文档到电脑,查找使用更方便
还剩1页未读,继续阅读
你可能喜欢<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
您的访问请求被拒绝 403 Forbidden - ITeye技术社区
您的访问请求被拒绝
亲爱的会员,您的IP地址所在网段被ITeye拒绝服务,这可能是以下两种情况导致:
一、您所在的网段内有网络爬虫大量抓取ITeye网页,为保证其他人流畅的访问ITeye,该网段被ITeye拒绝
二、您通过某个代理服务器访问ITeye网站,该代理服务器被网络爬虫利用,大量抓取ITeye网页
请您点击按钮解除封锁&Posts - 207,
Articles - 0,
Comments - 1310
11:20 by 贺臣, ... 阅读,
一. 使用JSONp方式调用
  不做详细讲解,可以参考jq文档
二. 服务端配置
  修改Web.config 文件
&system.webServer&
&modules runAllManagedModulesForAllRequests="true"&&/modules&
&httpProtocol&
&customHeaders&
&add name="Access-Control-Allow-Origin" value="*"/&
&add name="Access-Control-Allow-Headers" value="Content-Type"/&
&add name="Access-Control-Allow-Methods" value="GET,POST,PUT,DELETE"/&
&/customHeaders&
&/httpProtocol&
&/system.webServer&
  客户端调用代码如下
var param = {};
var msg = "dafdasfdsaf";
param["userName"] = "1";
param["passWord"] = "1";
param["code"] = "3323";
url: "http://www./UserAjax/Login?t=" + Math.random(),
data: param,
type: "post",
async:false,
success: function (result) {
alert(result);
alert(msg+"ddddddddddFFFFFFFFFFFFFFFF");
  经过测试调用成功,可以用于手机端的调用浅谈WEB跨域的实现(前端向)
分类:其他|标签:其他|日期:
同源策略/SOP(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击(可以参考我的)。
SOP要求两个通讯地址的协议、域名、端口号必须相同,否则两个地址的通讯将被浏览器视为不安全的,并被block下来。比如“http页面”和“https页面”属于不同协议;“qq.com”、“”、“”都属于不同域名(或主机);“a.com”和“a.com:8000”属于不同端口号。这三种情况常规都是无法直接进行通讯的。
我们很容易模拟不同源的环境,用iframe来帮忙即可:
&!DOCTYPE html&
&head lang=&en&&
&meta charset=&UTF-8&&
&title&模拟跨域&/title&
&iframe src=&&&&/iframe&
window.frames[0].onload = function () {
alert(&1&);
上述代码在chrome中会输出blocking信息:
即我们无法监听百度首页文档onload的事件,因为top窗口跟iframe窗体是不同源的。
现代浏览器的确在安全性上下了不少功夫,除了上述提到的默认禁止非同源页面通讯,还新增了CSP(Content Security Policy)报头特性等安全限制功能。不过既然为了用户安全而关闭了一扇窗户,自然也会为开发者开启一扇便利的窗户,要突破SOP的限制,咱还是有不少办法和花样的。
HTML5解决方案& &1. Cross-document messaging& &2. WebSocket
iframe形式& &1. document.domain& &2. location.hash& &3. window.name
其它形式& &1. 服务器代理& &2. flash socket
同域安全策略CORS(Cross-Origin Resource Sharing)是W3C在05年提出的跨域资源请求机制,它要求当前域(常规为存放资源的服务器)在响应报头添加Access-Control-Allow-Origin标签,从而允许指定域的站点访问当前域上的资源。我们使用node/iojs来模拟一下(不懂node/iojs?不急,先看下我的):
服务器端:
require(&http&).createServer(function(req,res){
//报头添加Access-Control-Allow-Origin标签,值为特定的URL或“*”
//“*”表示允许所有域访问当前域
res.setHeader(&Access-Control-Allow-Origin&,&*&);
res.end(&OK&);
}).listen(1234);
&!DOCTYPE html&
&head lang=&en&&
&meta charset=&UTF-8&&
&title&CORS&/title&
&script src=&jq.js&&&/script&
&div&catching data...&/div&
url:&http://127.0.0.1:1234/&,
success:function(data){
$(&div&).text(data)
运行客户端页面后,便能看到div内容成功变为服务端发来的“OK”,实现了两个不同域的页面间的通讯。通过上述代码我们也发现,CORS主要是在服务端上的实现(也不外乎是添加一个报头标签),客户端的实现跟常规的请求没啥出入。
不过CORS默认只支持GET/POST这两种http请求类型,如果要开启PUT/DELETE之类的方式,需要在服务端在添加一个&Access-Control-Allow-Methods&报头标签:
require(&http&).createServer(function(req,res){
res.setHeader(&Access-Control-Allow-Origin&,&http://127.0.0.1&);
res.setHeader(
&Access-Control-Allow-Methods&,
&PUT, GET, POST, DELETE, HEAD, PATCH&
res.end(req.method+& &+req.url);
}).listen(1234);
恼人的IE8-是不支持上述的CORS滴,不过不走寻常路的巨硬在IE8开始引入了XDR(XDomainRequest)新特性(IE11已经不再支持该特性),它实现了CORS的部分规范,只支持GET/POST形式的请求。另外在协议部分只支持 http 和 https 。
在服务器端,依旧要求在响应报头添加&Access-Control-Allow-Methods&标签(这点跟CORS一致)。
在客户端,DR对象的使用方法与XHR对象非常相似,也是创建一个XDomainRequest的实例,调用open()方法,再调用send()方法。但与XHR对象的open()方法不同,XDR对象的open()方法只接收两个参数:请求的类型和URL,因为所有XDR请求都是异步执行的,不能用它来创建同步请求。
请求返回之后,会触发load事件,相应的数据也会保存在responseText属性中,如下所示:
var xdr = new XDomainRequest();
xdr.onload = function() {
alert(xdr.responseText);
xdr.onerror = function() {
alert(&一个错误发生了!&);
xdr.open(&get&, &http://127.0.0.1:1234/&);
xdr.send(null);
由于XDR实在太过时,这里不做太多介绍,了解下即可,更多细节请查阅。
HTML5解决方案
1.&Cross-document messaging
在 Cross-document messaging 中,我们可以使用 postMessage&方法和 onmessage 事件来实现不同域之间的通信,其中postMessage用于实时向接收信息的页面发送消息,其语法为:
& otherWindow.postMessage(message, targetOrigin);
otherWindow: 对接收信息页面的window的引用。可以是页面中iframe的contentWindow属性;window.open的返回值;通过name或下标从window.frames取到的值。message: 所要发送的数据,string类型。targetOrigin: 允许通信的域的url,“*”表示不作限制。
我们可以在父页面中嵌入不同域的子页面(iframe实现,而且常规会把它隐藏掉),在子页面调用 postMessage 方法向父页面发送数据:
父页面(http://localhost:10847/sop/a.html):
&!DOCTYPE html&
&head lang=&en&&
&meta charset=&UTF-8&&
&title&postMessage&/title&
&iframe style=&display:& id=&ifr& src=&http://127.0.0.1:10847/sop/b.html&&&/iframe&
&script type=&text/javascript&&
window.addEventListener('message', function(event){
// 通过origin属性判断消息来源地址
if (event.origin == 'http://127.0.0.1:10847') {
alert(event.data);
// 弹出从子页面post过来的信息
}, false);
子页面(http://127.0.0.1:10847/sop/b.html):
&!DOCTYPE html&
&head lang=&en&&
&meta charset=&UTF-8&&
&title&子页面&/title&
&script type=&text/javascript&&
var ifr = window.
//获取父窗体
var targetOrigin = 'http://localhost:10847';
// 若写成 http://127.0.0.1:10847 则将无法执行postMessage
ifr.postMessage('这是传递给a.html的信息', targetOrigin);
执行如下:
关于 Cross-document messaging 的更多细节可参考。
2. WebSocket
WebSocket protocol 是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是server push技术的一种很棒的实现。
我们先简单看下webSocket在客户端上的api:
var ws = new WebSocket('ws://127.0.0.1:8080/url'); //新建一个WebSocket对象,注意服务器端的协议必须为“ws://”或“wss://”,其中ws开头是普通的websocket连接,wss是安全的websocket连接,类似于https。
ws.onopen = function() {
// 连接被打开时调用
ws.onerror = function(e) {
// 在出现错误时调用,例如在连接断掉时
ws.onclose = function() {
// 在连接被关闭时调用
ws.onmessage = function(msg) {
// 在服务器端向客户端发送消息时调用
// msg.data包含了消息
// 这里是如何给服务器端发送一些数据
ws.send('some data');
// 关闭套接口
ws.close();
服务端这块我们继续用node/iojs来编写,并使用模块辅助,socket.io很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容(例如替换为Flash Socket/Comet)。
我们先写服务端,首先我们得在项目根目录下使用npm命令安装好socket.io模块:
& npm install socket.io
接着新建服务端脚本(访问地址是http://127.0.0.1:1234/):
var io = require('socket.io');
var server = require(&http&).createServer(function(req,res){
res.writeHead(200, { 'Content-type': 'text/html'});
}).listen(1234);
io.listen(server).on('connection', function (client) {
client.on('message', function (msg) { //监听到信息处理
console.log('Message Received: ', msg);
client.send('服务器收到了信息:'+ msg);
client.on(&disconnect&, function() { //断开处理
console.log(&Server has disconnected&);
客户端页面(http://localhost:10847/sop/a.html,注意使用了socket.io之后,接口跟原生的不太一样了):
&!DOCTYPE html&
&head lang=&en&&
&meta charset=&UTF-8&&
&title&socket.io&/title&
&script src=&jq.js&&&/script&
&script src=&https://cdn.socket.io/socket.io-1.3.4.js&&&/script&
Incoming Chat:
&input type=&text& /&
$(function () {
var iosocket = io.connect('http://127.0.0.1:1234/'),
$ul = $(&ul&),
$input = $(&input&);
iosocket.on('connect', function() {
//接通处理
$ul.append($('&li&连上啦&/li&'));
iosocket.on('message', function(message) {
//收到信息处理
$ul.append($('&li&&/li&').text(message));
iosocket.on('disconnect', function() { //断开处理
$ul.append('&li&Disconnected&/li&');
$input.keypress(function (event) {
if (event.which == 13) { //回车
event.preventDefault();
iosocket.send($input.val());
$input.val('');
客户端页面执行效果如下:
WebSocket可以很好地摆脱无状态的http连接,从而很好地处理连接断开、数据错误的情况,不过缺点是兼容性还不够好,但咱可使用上述的socket.io来向下兼容。
这个实在用到烂大街了,提起跨域实现,其实最容易想到的就是它。JSONP(JSON with Padding)是JSON的一种“使用模式”,主要是利用script标签不受同源策略限制的特性,向跨域的服务器请求并返回一段JSON数据。
常规前后端会约定好某个JSONP请求的callback名(比如随便起个名字“abc”),服务端返回的JSON数据会被这个callback名包裹起来,进而方便服务器区分收到的请求,也方便客户端区分其收到的响应数据。我们可以利用jQuery轻松实现JSONP:
客户端(访问地址http://localhost:10847/sop/a.html):
&!DOCTYPE html&
&head lang=&en&&
&meta charset=&UTF-8&&
&title&JSONP&/title&
&script src=&jq.js&&&/script&
&div&&/div&
url:'http://127.0.0.1:1234/',
dataType:&jsonp&, //告知jQ我们走的JSONP形式
jsonpCallback:&abc&, //callback名
success:function(data){
console.log(data)
服务端(访问地址http://127.0.0.1:1234/&):
var http = require('http');
var urllib = require('url');
var data = {'name': 'vajoy', 'addr': 'shenzhen'};
http.createServer(function(req, res){
res.writeHead(200, { 'Content-type': 'text/plain'});
var params = urllib.parse(req.url, true);
//console.log(params);
if (params.query && params.query.callback) {
//console.log(params.query.callback);
params.query.callback + '(' + JSON.stringify(data) + ')';//jsonp
res.end(str);
res.end(JSON.stringify(data));//普通的json
}).listen(1234)
客户端执行结果:
不过JSONP始终是无状态连接,不能获悉连接状态和错误事件,而且只能走GET的形式。
iframe形式
在很久以前的石器时代,对于不支持 XMLHttpRequest 的浏览器的最佳回溯方法之一就是使用IFRAME对象,当然常规只是用它来实现流模式的Comet,而不是解决跨域通信的问题。
使用iframe跨域其实有点剑走偏锋的既视感,也存在一些限制性。下面均来介绍下。
1.&document.domain
该方法只适合主域相同但子域不同的情况,比如 a.com 和 ,我们只需要给这两个页面都加上一句&document.domain = 'a.com' ,就可以在其中一个页面嵌套另一个页面,然后进行窗体间的交互。
为了方便模拟环境,我们修改下hosts文件:
127.0.0.1 & & a.com127.0.0.1 & &
这样我们访问 a.com 的时候便能映射到本地了。
页面a.html(访问地址http://a.com:8080/sop/a.html):
&!DOCTYPE html&
&head lang=&en&&
&meta charset=&UTF-8&&
&title&iframe&/title&
&script src=&jq.js&&&/script&
&iframe src=&:8080/sop/b.html&&&/iframe&
document.domain = 'a.com';
$(&iframe&).load(function(){
$(this).contents().find(&div&).text(&OK&)
页面b.html(访问地址:8080/sop/b.html):
&!DOCTYPE html&
&head lang=&en&&
&meta charset=&UTF-8&&
&title&b.html&/title&
&script src=&jq.js&&&/script&
&div&&/div&
document.domain = 'a.com';
这时候我们访问a.html会发现b.html里的内容被成功修改:
2.&location.hash
location.hash/url hash 是个好东西,在之前我们曾利用avalon前端路由来实现简单的SPA页面(),便是助力于location.hash。
利用url地址改变但不刷新页面的特性(在url: http://a.com#hello 中的 '#hello' 就是location.hash,改变hash并不会导致页面刷新,所以可以利用hash值来进行数据传递)和iframe,我们可以实现跨域传递简单信息。
不过这个实现略麻烦,常规我们会想,在a.html下嵌套一个不同域的b.html,然后 a 和 b 互相修改彼此的hash值,也不断监听自己的hash值,从而实现我们的需求。可惜的是,大部分浏览器不允许修改不同域的父窗体的hash值(parent.location.hash),也就是说a虽能修改b的hash值,但反过来由b修改a的hash值却不成立。
为了解除该限制,我们可以在b页面中增加一个和a同域的iframe(c.html)来做代理,这样b可以修改c,而c可以修改a(即修改parent.parent.location.hash,别忘了a和c同域哦)。下面直接模拟这三个页面,做到让b向a传输信息(当然本质上是b向c,c再向a传输):
a.html(访问地址http://a.com:8080/sop/a.html):
&!DOCTYPE html&
&head lang=&en&&
&meta charset=&UTF-8&&
&title&iframe&/title&
&script src=&jq.js&&&/script&
&div&&/div&
&iframe src=&:8080/sop/b.html& style=&display:&&&/iframe&
var hash = &&;
function checkHash() {
var data = location.hash ? location.hash.substring(1) :
if (hash !== data) {
$(&div&).text('hash变化为:' + data);
setInterval(checkHash, 2000);
b.html(访问地址:8080/sop/b.html):
&!DOCTYPE html&
&head lang=&en&&
&meta charset=&UTF-8&&
&title&b.html&/title&
//有的浏览器(Firefox)还是可以直接操作parent.location.hash的
parent.location.hash = 'a=1&b=2';
} catch (e) {
// ie、chrome的安全机制无法修改parent.location.hash
// 所以要利用一个代理iframe
var ifrproxy = document.createElement('iframe');
ifrproxy.style.display = 'none';
ifrproxy.src = 'http://a.com:8080/sop/c.html#a=1&b=2'; //必须跟a.html同域
document.body.appendChild(ifrproxy);
c.html(访问地址http://a.com:8080/sop/c.html):
&!DOCTYPE html&
&head lang=&en&&
&meta charset=&UTF-8&&
&title&c.html&/title&
&script src=&jq.js&&&/script&
//因为parent.parent和自身属于同一个域,所以可以改变其location.hash的值
parent.parent.location.hash = self.location.hash.substring(1);
访问a.html后,效果如下:
成功传递了数据“a=1&b=2”。该方法优点是兼容较好,缺点却显而易见——可传递的数据类型、长度均受限,数据还是直接显示在url上的,不够安全。另外其实现也较麻烦,还要搞setInterval不断监听,跟轮询没区别了。
3.&window.name
window.name 的美妙之处在于,窗体的name值在页面跳转后依旧存在、保持原值(即使跳转的页面不同域),并且可以支持非常长的 name 值(2MB)。
如果我们在a页面需要和不同域的b页面通信,我们可以现在a页面嵌入b页面,待b页面有数据要传递时,把数据附加到b页面窗口的window.name上,然后把窗口跳转到一个和a页面同域的c页面,这样a就能轻松获取到内嵌窗体(地址已由跨域的b变为同域的c)的window.name了(如果需要,获取到数据后再把c跳转到b,并重复循环前面的步骤,同时a页面以setInterval的形式来达到轮询的效果)。我们继续模拟这三个页面:
a.html(访问地址http://a.com:8080/sop/a.html):
&!DOCTYPE html&
&head lang=&en&&
&meta charset=&UTF-8&&
&title&window.name&/title&
&script src=&jq.js&&&/script&
&div&&/div&
&iframe src=&:8080/sop/b.html& style=&display:&&&/iframe&
varifr = window.frames[0],
data = &&;
function checkData(){
loc = ifr.
if(loc.host){ //获取到了,说明iframe已转到同域的c页面
if(ifr.name !== data){ //说明有新数据
data = ifr.
$(&div&).text(JSON.parse(data).name);
ifr.location = &:8080/sop/b.html&; //数据收到后重回b页面接收新数据
setInterval(checkData,2000); //每2秒轮询一次
b.html(访问地址:8080/sop/b.html):
&!DOCTYPE html&
&head lang=&en&&
&meta charset=&UTF-8&&
&title&b.html&/title&
window.name = '{&name&:&vajoy&,&addr&:&shenzhen&}';
location = &http://a.com:8080/sop/c.html&; //跳转到和a同域的c页面
c.html页面啥都不用写,纯粹一个空的html即可,毕竟只是一个代理页面罢了。
我们访问a页面,会成功收到来自不同域b的数据:
1. 服务器代理
页面直接向同域的服务端发请求,服务端进行跨域处理或爬虫后,再把数据返回给客户端页面。依旧用node/iojs来模拟服务端,下面的代码来自:
&!doctype html&
&meta charset=&utf-8&&
&meta name=&viewport& content=&initial-scale=1, maximum-scale=1,user-scalable=no&&
&title&proxy_test&/title&
var f = function(data){
alert(data.name);
var xhr = new XMLHttpRequest();
xhr.onload = function(){
alert(xhr.responseText);
xhr.open('POST', 'http://localhost:8888/proxy?/arcgis/rest/services/World/GeocodeServer', true);
xhr.send(&f=json&);
var proxyUrl = &&;
if (req.url.indexOf('?') & -1) {
proxyUrl = req.url.substr(req.url.indexOf('?') + 1);
console.log(proxyUrl);
if (req.method === 'GET') {
request.get(proxyUrl).pipe(res);
} else if (req.method === 'POST') {
var post = '';
//定义了一个post变量,用于暂存请求体的信息
req.on('data', function(chunk){
//通过req的data事件监听函数,每当接受到请求体的数据,就累加到post变量中
req.on('end', function(){
//在end事件触发后,通过querystring.parse将post解析为真正的POST请求格式,然后向客户端返回。
post = qs.parse(post);
method: 'POST',
url: proxyUrl,
form: post
}).pipe(res);
2. flash socket
其实在前面介绍socket.io的时候就有提到,在不兼容WebSocket的浏览器下,socket.io会以flash socket或Comet的形式来兼容,而flash socket是支持跨域通信的形式,跟WebSocket一样走的TCP/IP套接字协议。具体的实现可参考,本文不赘述。
至此便介绍了这么几种常用的跨域通信的实现方式,希望对你能有所帮助。
大过年的还这么辛苦写文章我也是疯了,anyway,祝各位新春快乐,新的一年扬眉吐气、万事顺利!
文章署名:
文章地址:
优质IT资料分享网,由广大资源爱好者通过共享互助而共享各种学习资料,但本站无法保证所共享,资料的完整性和合理性
如果有资料对您的合法权益造成侵害,请立即联系我们处理}

我要回帖

更多关于 js解决跨域问题 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信