转自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虽然能用,但两个域间必须依据严格的协议,恕我直言它既不灵活也不优雅

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#)

  1. protected void Page_Load(object sender, EventArgs e)
  2.  {
  3.      String data = String.Empty;
  4.      String returnJSONStr = String.Empty;
  5.  
  6.      switch (Request.HttpMethod)
  7.      {
  8.          case "GET":
  9.              data = Request.QueryString["Data"];
  10.              returnJSONStr = "{\"Data\":\"Hi remote friend, you tried to passed me data: *" + data + "* through HTTP GET.\"}";
  11.              break;
  12.          case "POST":
  13.              data = Request.Form["Data"];
  14.              returnJSONStr = "{\"Data\":\"Hi remote friend, you tried to POST some mock data: *" + data + "* to me.\"}";
  15.              break;
  16.          case "OPTIONS":
  17.              break;
  18.          default:
  19.              returnBadRequestResponse();
  20.              break;
  21.      }
  22.  
  23.      if (String.IsNullOrEmpty(data))
  24.          returnBadRequestResponse();
  25.      else
  26.      {
  27.          Response.AddHeader("Access-Control-Allow-Origin", "*");
  28.          Response.ContentType = "application/json";
  29.          Response.Write(returnJSONStr);
  30.      }
  31.  }
  32.  
  33.  private void returnBadRequestResponse()
  34.  {
  35.      Response.StatusCode = 400;
  36.      Response.ContentType = "application/json";
  37.      Response.Write("{\"Error\":\"Bad HTTP request type!\"}");
  38.  }

  

 

PHP

  1. if(isset($["Data"])) 
  2.  { 
  3.      $method=$_SERVER['REQUEST_METHOD']; 
  4.      $data=""; 
  5.      if($method=="POST") 
  6.      { 
  7.          $data=$_POST["Data"]; 
  8.  
  9.          $fakeData=new FakeData(); 
  10.          $fakeData->Data="Hi remote friend, you tried to POST some mock data: *"+data+"* to me."; 
  11.          $fakeData->Time=new DateTime("now"); 
  12.      } 
  13.      elseif($method=="GET") 
  14.      { 
  15.          $fakeData=new FakeData(); 
  16.          $fakeData->Data="Hi remote friend, you tried to passed me data: *"+data+"* through HTTP GET."; 
  17.          $fakeData->Time=new DateTime("now"); 
  18.      } 
  19.      else 
  20.      { 
  21.          RaiseError(); 
  22.      } 
  23.  
  24.      header('Content-type: application/json'); 
  25.      $jsonStr= json_encode($fakeData); 
  26.      echo($jsonStr); 
  27.  } 
  28.  else 
  29.  { 
  30.      RaiseError(); 
  31.  } 
  32.  
  33.  function RaiseError() 
  34.  { 
  35.      http_send_status(405); 
  36.      header("Status: 405 Method Not Allowed"); 
  37.  } 
  38.  
  39.  /*Classes definition*/ 
  40.  class FakeData 
  41.  { 
  42.      public $Data; 
  43.      public $Time; 
  44.  }

  

客户端AJAXY发起请求代码:

  1. var cor = null; // cor stands for Cross-Origin request
  2.  
  3.  if (window.XMLHttpRequest) {
  4.      cor = new XMLHttpRequest();
  5.  }
  6.  //else if (window.XDomainRequest) {
  7.      //cor = new XDomainRequest();
  8.  //}
  9.  else {
  10.      alert("Your browser does not support Cross-Origin request!");
  11.      return;
  12.  }
  13.  
  14.  cor.onreadystatechange = function () {
  15.      if (cor.readyState == 4) {
  16.          document.getElementById('lbl').innerHTML = cor.responseText;
  17.      }
  18.  };
  19.  
  20.  var data = 'Some fake data';
  21.  if (method == 'POST') {
  22.      cor.open('POST', 'http://WayneYe.com/Demo/CORSDemo/CORSDemoServer.aspx', true);
  23.      cor.withCredential = "true";
  24.      cor.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  25.      cor.send('Data=' + data);
  26.  }
  27.  else if (method == 'GET') {
  28.  
  29.      cor.open('GET', 'http://WayneYe.com/Demo/CORSDemo/CORSDemoServer.aspx?Data=' + data, true);
  30.      cor.withCredential = "true";
  31.      cor.send(null);
  32.  }

  

 

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等等并不是很实用的方法。

参考资料

[转]AJAX 跨源 HTTP 请求的更多相关文章

  1. WebApi 自定义过滤器实现支持AJAX跨域的请求

    我想关于此类话题的文章,大家一搜铺天盖地都是,我写此文的目的,只是对自己学习过程的记录,能对需要的朋友有所帮助,也百感荣幸!!!废话不多说,直接上代码! 客户端:很简单的AJAX请求 <html ...

  2. ajax跨域简单请求与复杂请求

    开发网站时经常会用到跨域资源共享(简称cors,后面使用简称)来解决跨域问题,但是在使用cors的时候,http请求会被划分为两类,简单请求和复杂请求,而这两种请求的区别主要在于是否会触发cors预检 ...

  3. 彻底掌握CORS跨源资源共享

    本文来自于公众号链接: 彻底掌握CORS跨源资源共享 ) 本文接上篇公众号文章:彻底理解浏览器同源策略SOP 一.概述 在云时代,各种SAAS应用层出不穷,各种互联网API接口越来越丰富,H5技术在微 ...

  4. (转)AJax跨域:No 'Access-Control-Allow-Origin' header is present on the requested resource

    在本地用ajax跨域访问请求时报错: No 'Access-Control-Allow-Origin' header is present on the requested resource. Ori ...

  5. 跨源资源共享(CORS)概念、实现(用Spring)、起源介绍

    本文内容引用自: https://howtodoinjava.com/spring5/webmvc/spring-mvc-cors-configuration/ https://developer.m ...

  6. 关于ajax跨域的一些说说

    跨域:跨当然是跨过去,域当然是别的服务器 (说白点就是去别服务器上取东西) 只要协议.域名.端口有任何一个不同,都被当作是不同的域 ajax 是一种请求响应无刷新技术(xmlhttqrequest对象 ...

  7. WebService跨域配置、Ajax跨域请求、附开发过程源码

    项目开发过程中需要和其他公司的数据对接,当时我们公司提供的是WebService,本地测试,都是好的,Ajax跨域请求,就报错,配置WebService过程中,花了不少功夫,入不少坑,不过最终问题还是 ...

  8. java、ajax 跨域请求解决方案('Access-Control-Allow-Origin' header is present on the requested resource. Origin '请求源' is therefore not allowed access.)

      1.情景展示 ajax调取java服务器请求报错 报错信息如下: 'Access-Control-Allow-Origin' header is present on the requested ...

  9. Ajax操作如何实现跨域请求 (JSONP和CORS实现Ajax跨域的原理)

    由于浏览器存在同源策略机制,同源策略阻止ajax (XMLHttpRequest) 从一个源加载的文档或脚本获取或设置另一个源加载的文档的属性. 特别的:由于同源策略是浏览器的限制,所以请求的发送和响 ...

随机推荐

  1. 新版SourceTree免帐号登录安装

    http://blog.csdn.net/zcbyzcb/article/details/72959720?locationNum=2&fps=1 [ { "$id": & ...

  2. [转]ASP.NET MVC 5 - 创建连接字符串(Connection String)并使用SQL Server LocalDB

    您创建的MovieDBContext类负责处理连接到数据库,并将Movie对象映射到数据库记录的任务中.你可能会问一个问题,如何指定它将连接到数据库? 实际上,确实没有指定要使用的数据库,Entity ...

  3. Java 基本语法----进制、运算符

    进 制 对于整数,有四种表示方式: 二进制:0,1 ,满 2 进 1.以 0b 或 0B 开头.十进制:0-9 ,满 10 进 1. 八进制:0-7 ,满 8 进1. 以数字 0 开头表示.十六进制: ...

  4. php-新特性,生成器的创建和使用

    mark 一下~ http://laravelacademy.org/post/4317.html

  5. 一加氢OS发布会 观看小结

    观看地址:http://v.youku.com/v_show/id_XMTI0ODkzNTg5Mg==.html?from=s1.8-1-1.2八种基本色调.33%自由:top33%位置放壁纸,底部桌 ...

  6. 【整理】Virtualbox中的网络类型(NAT,桥接等),网卡,IP地址等方面的设置

    之前是把相关的内容,放到: [已解决]实现VirtualBox中的(Guest OS)Mac和主机(Host OS)Win7之间的文件和文件夹共享 中的,现在把关于网络配置方面内容,单独提取出来,专门 ...

  7. 上传控件CSS用图片代替

    <style type="text/css"> a.btn {width: 120px;height: 42px;overflow: hidden;display: b ...

  8. CodeForces - 459E Pashmak and Graph[贪心优化dp]

    E. Pashmak and Graph time limit per test 1 second memory limit per test 256 megabytes input standard ...

  9. hdu1024 Max Sum Plus Plus[降维优化好题(貌似以后可以不用单调队列了)]

    Max Sum Plus Plus Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...

  10. all index range ref eq_ref const system 索引type说明

    背景知识 在使用sql的过程中经常需要建立索引,而每种索引是怎么处罚的又是怎么起到作用的,首先必须知道索引和索引的类型. 索引类型type 我们可以清楚的看到type那一栏有index ALL eq_ ...