如何解决 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 劫持。就像这样:&
&
这样就会弹出 test.json 中所有 key 为 “id” 的值。
或者这样:var arrData;
Array = function() {
arrData = this;
};
这样通过 arrData 也能访问到 JSON 数据。
现代浏览器早就把这些漏洞封死了,如果你能找到可以在前端劫持 JSON 的通用漏洞,那卖给黑产小哥都够你大赚一笔的了。首先假设你请求数据的网站为B。要看你是否可以控制(修改里面的代码)。
1 jsonp 缺点 只能get请求 ,需要修改B网站的代码2 cors 刘子龙说的方案,这个方案缺点 是 ie6 7 兼容不好(倒是不见得要兼容)。需要B网站在响应中加头3 postMessage 缺点也是 ie6 7 兼容不好(倒是不见得要兼容)。需要修改B网站的代码4 iframe window.name 传值得方式很巧妙,兼容性也很好。但是也是需要你能修改B网站代码5 服务端主动请求B网站,兼容性好而且你客户端的代码还是原来的ajax,缺点是感觉不好。。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.comphp程序这样写: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方式,利用&
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 |