ajax跨域解决方案

一、什么是AJAX? Asynchronous JavaScript and XML (Ajax ) 是驱动新一代 Web 站点(流行术语为 Web 2.0 站点)的关键技术。Ajax 允许在不干扰 Web 应用程序的显示和行为的情况下在后台进行数据检索。使用 XMLHttpRequest 函数获取数据,它是一种 API,允许客户端 JavaScript 通过 HTTP 连接到远程服务器。Ajax 也是许多 mashup 的驱动力,它可将来自多个地方的内容集成为单一 Web 应用程序。

二、为什么会有这个问题? ajax本身实际上是通过XMLHttpRequest对象来进行数据的交互,而浏览器出于安全考虑,不允许js代码进行跨域操作,所以会警告。

三、常见解决办法

(1)使用script标签。 script调用没有域的限制,我们可以将输出的数据伪装成script的变量。

(2)服务端脚本中转 服务端脚本使用XMLHTTP没有域的限制,但是耗费服务器的资源。

(3)利用iframe 在同一个域名的各个子域名下,如果设置了document.domain,那么是可以相互调用JS的。

(4)JSONP 这个方法也是最解决正常AJAX和多人使用的。 JSONP(JSON with Padding)是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问(这仅仅是JSONP简单的实现形式)。 首先在客户端注册一个callback, 然后把callback的名字传给服务器。 此时,服务器先生成 json 数据。 然后以 javascript 语法的方式,生成一个function , function 名字就是传递上来的参数 jsonp. 最后将 json 数据直接以入参的方式,放置到 function 中,这样就生成了一段 js 语法的文档,返回给客户端。 客户端浏览器,解析script标签,并执行返回的 javascript 文档,此时数据作为参数,传入到了客户端预先定义好的 callback 函数里.(动态执行回调函数)。

(5)CORS CORS-CrossOrigin Resources Sharing,也即跨源资源共享,它定义了一种浏览器和服务器交互的方式来确定是否允许跨域请求。它是一个妥协,有更大的灵活性,但比起简单地允许所有这些的要求来说更加安全。简言之,CORS就是为了让AJAX可以实现可控的跨域访问而生的。

但是CORS也具有一定的风险性,比如请求中只能说明来自于一个特定的域但不能验证是否可信,而且也容易被第三方入侵。

nginx增加类似如下配置:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. server {  
  2.     location / {  
  3.         if ($request_method = 'OPTIONS') {  
  4.           add_header 'Access-Control-Allow-Origin' '*';  
  5.           add_header 'Access-Control-Allow-Credentials' 'true';  
  6.           add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';  
  7.           add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';  
  8.          # add_header 'Access-Control-Max-Age' 1728000;  
  9.           add_header 'Content-Type' 'text/plain charset=UTF-8';  
  10.           add_header 'Content-Length' 0;  
  11.           return 200;  
  12.         }  
  13. }  

如果没有nginx转发,java需要如下代码: 

[html] view plaincopy在CODE上查看代码片派生到我的代码片
 
    1. rundata.getResponse().addHeader("Access-Control-Allow-Origin", "*");  
    2. rundata.getResponse().addHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");  
    3. rundata.getResponse().addHeader("Access-Control-Allow-Headers", "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With");  

Tomcat下的配置 下载cors-filter-1.7.jar,java-property-utils-1.9.jar这两个库文件,放到lib目录下。(可在 http://search.maven.org上查询并下载。)工程项目中web.xml中的配置如下: 

 

[html] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. <filter>  
  2.     <filter-name>CORS</filter-name>  
  3.     <filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>  
  4.     <init-param>  
  5.      <param-name>cors.allowOrigin</param-name>  
  6.         <param-value>*</param-value>  
  7.     </init-param>  
  8.     <init-param>  
  9.      <param-name>cors.supportedMethods</param-name>  
  10.         <param-value>GET, POST, HEAD, PUT, DELETE</param-value>  
  11.     </init-param>  
  12.     <init-param>  
  13.      <param-name>cors.supportedHeaders</param-name>  
  14.         <param-value>Accept, Origin, X-Requested-With, Content-Type, Last-Modified</param-value>  
  15.     </init-param>  
  16.     <init-param>  
  17.         <param-name>cors.exposedHeaders</param-name>  
  18.         <param-value>Set-Cookie</param-value>  
  19.     </init-param>  
  20.     <init-param>  
  21.         <param-name>cors.supportsCredentials</param-name>  
  22.         <param-value>true</param-value>  
  23.     </init-param>  
  24. </filter>  
  25. <filter-mapping>  
  26.     <filter-name>CORS</filter-name>  
  27.     <url-pattern>/*</url-pattern>  
  28. </filter-mapping>  

 

 

假设我们页面或者应用已在 http://www.test1.com 上了,而我们打算从 http://www.test2.com 请求提取数据。一般情况下,如果我们直接使用 AJAX 来请求将会失败,浏览器也会返回“源不匹配”的错误,"跨域"也就以此由来。
  利用 CORS,http://www.test2.com 只需添加一个标头,就可以允许来自 http://www.test1.com 的请求,下图是我在PHP中的 hander() 设置,“*”号表示允许任何域向我们的服务端提交请求
     

  也可以设置指定的域名,如域名 http://www.test2.com ,那么就允许来自这个域名的请求

     

 

1.第一步 设置响应头

header('Access-Control-Allow-Origin:*');  //支持全域名访问,不安全,部署后需要固定限制为客户端网址

header('Access-Control-Allow-Methods:POST,GET,OPTIONS,DELETE'); //支持的http 动作

header('Access-Control-Allow-Headers:x-requested-with,content-type');  //响应头 请按照自己需求添加。

2.第二部 了解IE chrome 等浏览器 对于 跨域请求并要求设置Headers自定义参数的时候的 "预请求"   就是如果遇到 跨域并设置headers的请求,所有请求需要两步完成!

A 第一步:发送预请求 OPTIONS 请求。此时 服务器端需要对于OPTIONS请求作出响应 一般使用202响应即可 不用返回任何内容信息。(能看到这份手稿的人,本人不相信你后台处理不了一个options请求)

B 第二步:服务器accepted 第一步请求后 浏览器自动执行第二步 发送真正的请求。此时 大多数人 会发现请求成功了,但是 有那么几个人会发现 请求成功了但是没有任何信息返回 why?因为你自定义的请求头在服务器响应中不存在!

查看console输出 会发现一个问题:

“Access-Control-Allow-Headers 列表中不存在请求标头 XXXXXX”【IE】,

request header field xxxxxx is not allowed by Access-Control-Allow-Header【chrome】

这是因为 你的XXXX请求头 没有在服务器端被允许哦~

遇到这个问题 只有通过修改服务器端来完成,举例:需要设置 requesttype这么一个自定义头,那么 你需要在 服务端里面 将header('Access-Control-Allow-Headers:x-requested-with,content-type,requesttype');  同学们自行体会吧 这种语法就是根据“,”分割 自己需要设置什么头,必须要在 服务端请求的响应头里面设置好,不然客户端永远永远提交不上去!

至此  JavaScript/ajax  跨域+ 修改httpheader 任务完美实现。前端 后端完全分离 大道自成!前后期分离迎来旷古的潮流

 次处作为见证 2016年1月25日20:21:28

"人们都一直在抱怨 JavaScript同源策略限制了web前端的发展!然而是服务端做的不够细致!"

部分代码参考如下:代码只是提供了思想,具体步骤还要根据以上的文字 自行揣摩实现。以上内容看不懂 说明对于web一点也不了解,需要买本书看看喽~(本人个人经历成功实现。若有人遇到同样的问题可以 加群245961308)

客户端代码:

 

服务器端代码

 

posted @ 2016-02-25 10:41  Earic  阅读(519)  评论(0编辑  收藏  举报