標籤:

如何解决 Ajax 跨域请求不到的问题?

希望最好用原生js,可以掠去ajax方法体,而且能满足post需求,另外,请不要直接拷网上的“滥”了的文章。。。谢谢

增加一個問題:

我要用JS獲取一個網頁上面的內容, 一個JSON. 格式只能是: {"id" : xxx}.

我試過JSONP不成=.=

iframe的話, JS又訪問不了iframe內容(因為跨域). 又不可以用代理. 因為要用戶身份認證.

求教呀


跨域POST??啧啧啧

如果用现代浏览器,就用XHR 2.0的Access-Control-Allow吧

如果要兼容古代浏览器,请用iframe代理,这样把问题从“跨域POST”转化为“跨域iframe之间的通信”,条件是接收POST的域名要部署一个html文件作为跨域的“桥”来用,也就是说那个域名必须是受你控制的。


lz,不要多想了,如果要请求的服务器不是你控制的,那基本不可能了。

如果你可以控制要请求的服务器,那完全可以定制虾 用jsonp。什么iframe,window。name也都用不着了。。。


除非你有数据的控制权,能通过 JSONP 或者 CORS 等方法拿到数据,否则肯定没戏。这是个浏览器的原则问题,如果有跨域方法那肯定是浏览器漏洞,早晚会被修复。

在一些上古浏览器里可以使用上古漏洞,修改 Object 或 Array 的构造函数来进行 JSON 劫持。

就像这样:

&
Object.prototype.__defineSetter__("id", function(obj) {
alert(obj);
});
&

&

6 类似5 用nginx把B网站的数据url反向代理。

我觉得吧,

如果你不能修改B网站的代码老老实实5 6 方案

如果能修改B网站 方案2的修改应该是最简单的。

就算是B网站你可以修改,还有种需求处理起来比较麻烦的,就是有的数据需要登录之后才能取。

最直接的方案,B网站提供数据的url 进去先提供用户名密码,走下登录再走取数据,最后返回数据。

但是往往最直接的方案都不是好的方案。。。

(登录请求=》返回令牌=》带令牌请求受限数据)

所以最好用是方案2 然后B网站有oauth 功能,你的页面加个登陆后,用户登陆后客户端保存好token_key,然后取数据。(这个方案类似通过sessionid得到session。因为安全相关的原因,通过通过sessionid得到session 这样的需求并不是所有语言的所有框架都会提供的)

当然oauth方案也有坏处,就是B网站本来没有oauth,要加上一个会略麻烦。

所以还可以选择方案2 加上withcredentials=true 这个方案。当然登录页面还是需要的

这个问题已经是4年前的了,不过跨域请求似乎是个永恒的问题,正好最几天刚刚也遇到了类似的需求,就写得多了一点了。最近需要将原来的一个web网站写成手机版本,我是用的html5 加cordova 打包成手机程序的, 方案2 cors 然后加withcredentials=true 然后在登录请求后重写手机客户端的cookie 方案能很好满足我的需求。 希望对大家有帮助


既然这样,为何舍近取远呢?这才叫做最原生的处理方法。

方法1

服务器端直接设置header内容

Access-Control-Allow-Origin:*

或者

Access-Control-Allow-Origin:htt@p://http://api.zhihu.com

这样就可以直接请求到任何网站或者htt@p://http://api.zhihu.com

php程序这样写:

header("Access-Control-Allow-Origin:*");

或者

header("Access-Control-Allow-Origin:htt@p://api.zhihu.com");

(注意去掉@,知乎编辑器不知道怎么不让带http的网址自动链接,先这样写了)

方法2

在Nginx设置”头信息“直接添加Access-Control-Allow-Origin:*的信息。


尽量让前端简化吧 在我看来最简单最直接的方案不过两种:

1. 配置目标服务器的CORS

2. 如果觉得CORS有学习成本,最简单的办法就是加一个“转发”的路由,注意这里不是“跳转”,因为跳转同样会遇到跨域问题。


jsonp 是写 script 标签,只能满足 get 请求。跨域 post 的话,IE8 及以上和其他主流浏览器可以用 window.postMessage 来实现,也就是传说中的 HTML5 方法了,可以看下标准,代码很简单。IE6、7 就用老式的方法,隐藏的 form,target 指向一个隐藏的 iframe,然后调 form 的 submit,服务端返回的结果会刷到 iframe 里。

不过这两种方法一般都需要服务端做一定的配合,要是不能操作接口所在的服务器(比如调第三方的接口),那就只能在自己的服务端上做代理了。


所有使用JSON的方案都有一个错误,就是无法实现POST。

那目前实现POST的方法是

1、建立一个iframe,iframe内的JS创建一个form表单,并可以将接收到的参数放入表单中POST提交。

2、将iframe页面插入到页面中。

3、针对现代浏览器,将数据通过postMessage()方法传入iframe中。针对不支持此方法的浏览器,通过URL HASH的方法将参数传入iframe中。

(由于URL有长度限制,所以不能传播大数据)

除此方法外,可以使用window.name的方案,但此方案我没有实现过,具体可以百度一下张克军写的事例。


JSONP是JS跨域的hacker写法,是伪跨域的,需要服务器端配合返回回调,而且参数是JSON格式。

HTML5支持form的跨域操作,传递二进制都没有问题,XMLHTTPRequest 2.0也可以实现相应异步操作。属于官方跨域的操作方式,前提是需要服务器端设置header里接收所有域或者指定域的请求,而且是不全兼容的。

总结来说,两种方式都是需要服务器支持的。

另外谈下代理的事情,如果只是用户身份认证的话,其实是可以通过后台语言解决的。python的requests,urllib还有php的curl等都是可以做到模拟用户登录的,前提是服务器后台没做防盗链。

如果做代理也搞不定的话,还是有方法的。

基于chrome扩展的开发,是可以让你的前端代码访问到网页的DOM的,你的代码能拿到数据,想向自己服务器的本域或者跨域提交都有已知的解决方案了。


跨域json访问是对安全很敏感的问题,解决的方案有两大类:

第一类:浏览器原生支持的方案:

此类方案的前提是json请求发起方和接收方都需要把对方的url加入信任列表。

下图就是此类方案的两个具体实现。

1. 直接用ajax请求,在请求header中写明origin,接收方响应请求中返回access-control-allow-origin。

2. 在html中内嵌一个iframe,用window.postMessage方法发送消息给iframe(通常是接收方网址)。在接收方iframe中监听windows 的message事件,校验其中的origin参数确定在信任列表里,返回结果。

3. JSONP方式,利用&的src可以跨域的特点,接收方根据js src参数返回js内容

第二类:服务器端伪造同源请求接收方是通过request的header中的字段来判断是否同源的(referer,origin等),浏览器为了安全不能修改ajax请求的header,但服务器可以伪造同源的请求。


现在使用浏览跨域除了JSONP, 还有一种就是让服务器端支持跨域,前面的有人回答已经说了,设置响应头 Access-Control-Allow-Origin: * 。 除此之外需要特别注意的是对于POST、PUT和Delete的跨域请求之前, 浏览器会发起一个OPTIONS Method 的预请求来获得一些资源的信息,因此服务器必须支持OPTIONS才能完成 POST、PUT和Delete的跨域请求, 有些服务器不支持或者默认会禁止这些比较不安全的请求,所以还需要您设置Access-Control-Allow-Methods:GET, POST, PUT, DELETE,HEAD, OPTIONS。


跨域问题,目前地球上最好、最方便(没有之一)的解决方案是,利用Apache转发。

原因有2:

1.前台后台的代码都不需要改动,也不需要为跨域去专门写代码或改代码。

2.Apache非常容易安装:Win上有WAMP,Linux上有LAMP;且Apache的转发设置起来非常简单方便。开发时甚至可以直接把转发配置为客户端到VS或Eclipse,方便调试;上线后把转发切换成客户端到Apache自身或IIS或Tomcat或WebLogic或Nginx等等。


header("Access-Control-Allow-Origin:*")


jsonp对内容的长度有限制,最多也就能传几百字节。

要大量内容的话,只能创建一个form,动态输入input,然后调用它的submit方法。

将submit的结果放到一个iframe中,就可以显示返回值。

p.s 目前看到最好的跨域解决方案是window.name跨域传递,可以无缝传输最大2M的数据。具体方案见:

http://www.cnblogs.com/rainman/archive/2011/02/21/1960044.html


使用json,就是使用 &< script &> 标签,实现伪ajax.

我一般使用jq.给你个jq的例子.

$.ajax({

url: http://xxx.xxx/json.php,

dataType:"jsonp",

timeout : 3000 ,//毫秒

data : "foo=bar1foo=bar2",

//jsonpCallback:"jsoncallback",

beforeSend :function(){

},

error:function(item){

alert("加载失败");

},

success: function(item){

alert( item.items[0].media.m);

},

complete: function(){

}

});

json.php

&< ?php

header("Content-type: application/json");

$results = array("key" = &> "value","key1"= &> array("a"= &> "ok"));

echo $_GET["callback"] . "(" . json_encode($results) . ")";

? &>


直接在服务器端允许跨域就可以了 很简单,具体就是修改HTTP头

比如webpy中:

185 web.header("Access-Control-Allow-Origin", "*")

186 web.header("Access-Control-Allow-Credentials", "true")

把这两句加在view中, 即在每个类的GET和POST方法的开始加上这两句就可以了

其他的语言类似


服务器端代理


window.name 也是一种解决办法


推薦閱讀:

訪問localhost和127.0.0.1是否完全一樣?
知乎網站的性能都有些什麼瓶頸?可以以何種技術和方式解決?
學習Ajax,關於XMLHttpRequest對象是怎麼從後台和伺服器交換數據的不太理解?
如今的網站是否可以設計成只有一個html(內容框架),全站無跳轉?

TAG:JavaScript | Ajax |