zoukankan      html  css  js  c++  java
  • [转]AJAX 跨源 HTTP 请求

    转自OSChina, 原文: http://www.oschina.net/translate/ajax-cross-origin-http-request

    背景

    跨源HTTP请求(也称跨域AJAX请求)是大多数Web开发人员可能遇到的一个问题,根据同源策略,浏览器将限制客户端的JavaScript在一个安全沙箱内,通常JS不能直接同一台不同的域的远程服务器通信。在过去,开发者们创造了许多解决方法以实现跨域资源请求,常用的方法如下:

    1. 使用Flash/Silverlight或服务器端“代理”来与远程通讯 

    2. 带填充JSON (JSONP).

    3. 在iframe中嵌入远程服务器并通过fragment或window.name通信,参考这里。

    如此等等..

    这些解决方法或多或少都有问题,比如使用JSONP时若只是简单的“eval”将导致安全漏洞,#3虽然能用,但两个域间必须依据严格的协议,恕我直言它既不灵活也不优雅Smile | :)

    W3C已经引入了跨域资源共享 (CORS)作为能够解决该问题并提供安全、灵活以及推荐标准的解决方案。


     

    机制

    从较高的层次来看我们可以简单认为CORS 是介于 域A客户端 的AJAX调用 和一个托管在域B的页面 之间的契约, 一个典型的跨源 请求或者响应将会是这样:

    域 A 的 AJAX 请求头

    Host DomainB.com  
    User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0  
    Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8,application/json  
    Accept-Language en-us;  
    Accept-Encoding gzip, deflate  
    Keep-Alive 115  
     Origin http://DomainA.com 

    域 B 的 响应头

    Cache-Control private /> Content-Type application/json; charset=utf-8  
     Access-Control-Allow-Origin DomainA.com  
    Content-Length 87  
    Proxy-Connection Keep-Alive  
    Connection Keep-Alive

    我上面标记的蓝色部分是关键实现, "Origin" 请求头表示  跨源请求 或者 预检请求 源于哪里,  "Access-Control-Allow-Origin" 请求头 表示这个页面允许来自域A 的请求(其值为 * 表示允许任何域的远程请求)。

    像我上面提到的,W3 建议浏览器在提交实际跨源HTTP 请求前,实现“预检请求”, 简而言之,就是一个HTTP OPTIONS 请求:

    OPTIONS DomainB.com/foo.aspx HTTP/1.1

    如果 foo.aspx 支持 OPTIONS HTTP 指令, 它可能会像下面这样返回响应:

    HTTP/1.1 200 OK  
    Date: Wed, 01 Mar 2011 15:38:19 GMT  
    Access-Control-Allow-Origin:   http://DomainB.com  
    Access-Control-Allow-Methods: POST, GET, OPTIONS, HEAD  
    Access-Control-Allow-Headers: X-Requested-With  
    Access-Control-Max-Age: 1728000  
    Connection: Keep-Alive  
    Content-Type: application/json

    只有满足在响应中包含 "Access-Control-Allow-Origin" , 并且其值为 "*" 或者包含提交CORS请求的域,这些强制条件的浏览器才能提交正式的跨域请求, 并在 预检结果缓存” 中缓存请求结果 。


     

    实现

    让我们看一下服务器端代码,例子如下(ASP.NET和PHP)

    ASP.NET (C#)

    protected void Page_Load(object sender, EventArgs e)
     {
         String data = String.Empty;
         String returnJSONStr = String.Empty;
     
         switch (Request.HttpMethod)
         {
             case "GET":
                 data = Request.QueryString["Data"];
                 returnJSONStr = "{"Data":"Hi remote friend, you tried to passed me data: *" + data + "* through HTTP GET."}";
                 break;
             case "POST":
                 data = Request.Form["Data"];
                 returnJSONStr = "{"Data":"Hi remote friend, you tried to POST some mock data: *" + data + "* to me."}";
                 break;
             case "OPTIONS":
                 break;
             default:
                 returnBadRequestResponse();
                 break;
         }
     
         if (String.IsNullOrEmpty(data))
             returnBadRequestResponse();
         else
         {
             Response.AddHeader("Access-Control-Allow-Origin", "*");
             Response.ContentType = "application/json";
             Response.Write(returnJSONStr);
         }
     }
     
     private void returnBadRequestResponse()
     {
         Response.StatusCode = 400;
         Response.ContentType = "application/json";
         Response.Write("{"Error":"Bad HTTP request type!"}");
     }
    

      

     

    PHP

    if(isset($["Data"])) 
     { 
         $method=$_SERVER['REQUEST_METHOD']; 
         $data=""; 
         if($method=="POST") 
         { 
             $data=$_POST["Data"]; 
     
             $fakeData=new FakeData(); 
             $fakeData->Data="Hi remote friend, you tried to POST some mock data: *"+data+"* to me."; 
             $fakeData->Time=new DateTime("now"); 
         } 
         elseif($method=="GET") 
         { 
             $fakeData=new FakeData(); 
             $fakeData->Data="Hi remote friend, you tried to passed me data: *"+data+"* through HTTP GET."; 
             $fakeData->Time=new DateTime("now"); 
         } 
         else 
         { 
             RaiseError(); 
         } 
     
         header('Content-type: application/json'); 
         $jsonStr= json_encode($fakeData); 
         echo($jsonStr); 
     } 
     else 
     { 
         RaiseError(); 
     } 
     
     function RaiseError() 
     { 
         http_send_status(405); 
         header("Status: 405 Method Not Allowed"); 
     } 
     
     /*Classes definition*/ 
     class FakeData 
     { 
         public $Data; 
         public $Time; 
     }
    

      

    客户端AJAXY发起请求代码:

    var cor = null; // cor stands for Cross-Origin request
     
     if (window.XMLHttpRequest) {
         cor = new XMLHttpRequest();
     }
     //else if (window.XDomainRequest) {
         //cor = new XDomainRequest();
     //}
     else {
         alert("Your browser does not support Cross-Origin request!");
         return;
     }
     
     cor.onreadystatechange = function () {
         if (cor.readyState == 4) {
             document.getElementById('lbl').innerHTML = cor.responseText;
         }
     };
     
     var data = 'Some fake data';
     if (method == 'POST') {
         cor.open('POST', 'http://WayneYe.com/Demo/CORSDemo/CORSDemoServer.aspx', true);
         cor.withCredential = "true";
         cor.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
         cor.send('Data=' + data);
     }
     else if (method == 'GET') {
    
         cor.open('GET', 'http://WayneYe.com/Demo/CORSDemo/CORSDemoServer.aspx?Data=' + data, true);
         cor.withCredential = "true";
         cor.send(null);
     }
    

      

     

    JS代码适用于所有主流浏览器(IE8+, FF 3.6+, Chrome 8+),我没有用IE8所采用的XDomainObject,因为 IE8+, FF and Chrome, Safari等浏览器支持XMLHTTP请求。而且XDomainObject(XDR)似乎有很多限制(参考: http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx

    结论

    跨源资源共享为网站开发人员实现跨源通信提供了一个安全,灵活,标准的方案。也许是时候摈弃像JSONP,Flash,Silverlight,server bridge以及window.name等等并不是很实用的方法。

    参考资料

  • 相关阅读:
    一百多套开发视频教程的下载地址
    http://blog.csdn.net/chlele0105/article/details/9056951
    http://kb.cnblogs.com/page/541862/
    Linux版本选择
    2015-2016规划
    PHP 类的继承一些知识点汇总
    PHP面向对象的基本属性分析
    PHP中的魔术方法总结 :
    PHP字符串常用操作函数
    php八中数据类型以及相互转换
  • 原文地址:https://www.cnblogs.com/LeoWong/p/3702399.html
Copyright © 2011-2022 走看看