最近写前台请求后台数据,遇到这样的报错“Origin null is not allowed by Access-Control-Allow-Origin”,上网查了一下是跨域请求的问题。举个例子,如果你为你的web应用建立了一个web服务器,不过你又在这台服务器上去请求另一台服务器的数据,这种情况下跨域就会发生。跨域问题的出现本质是由于浏览器安全方面的限制,XMLHttpRequest只能访问同一域下的数据,其他的由于安全问题而拒绝访问。跨域问题分为多种情况,比如不同的域名;此外同一域名,但是不同协议,比如http和https也不可以;又比如同一个域名下,不同的端口可是不可以的。此外还有几种情况,上面的几种是比较经常会遇见的。
对于跨域访问的解决方法,网上给了几种:
1.利用 <script>标签进行解决。
不过这种方法需要和服务端那边进行配合,也就是需要在服务端编写代码来返回数据。 如果无法对服务端的代码进行修改的话这种方法是行不通的。当然,如果可以的话这种方法比proxy代理的方式要简单一些。用<script>标签进行跨域操作的原理是当浏览器请求一个js脚本的时候会同时解析并且运行脚本内的函数,从而通过服务器返回一些比如json对象数据等等。在网上找了一段样例如下:
var scriptBlock = document.createElement("script");
function StartGet() {
scriptBlock.src = "";
scriptBlock.src = "http://Domain2/GetData.aspx";
scriptBlock.type = "text/javascript";
scriptBlock.language = "javascript";
document.getElementsByTagName("head")[0].appendChild(scriptBlock);
scriptBlock.onreadystatechange = ReturnData;
}
function ReturnData() {
//alert(scriptBlock.readyState);
//uninitialized Object is not initialized with data.
//loading Object is loading its data.
//loaded Object has finished loading its data.
//interactive User can interact with the object even though it is not fully loaded.
//complete Object is completely initialized.
if("loaded" == scriptBlock.readyState) {
var div = document.getElementById("htmldiv");
div.innerHTML = a.project[0].name; //a是返回的json里面的变量
}
}
服务端的代码,从服务端的代码可见,服务端返回的是一个json的数组。
protected void Page_Load(object sender, EventArgs e)
{
Response.Write("var a = {'project':[{'name':'a1'},{'name':'a2'}]};");
}
对于这种方法,还是那句话,需要你有能力对服务端的代码做手脚才能使用~
2.使用web代理服务器进行跨域操作。
利用在同一台服务器上的Proxy,也就是经过中间代理服务器的转发。例如域A的页面JS需要访问域B下的链接获取数据,Proxy的方法即在域A的服务器端建立一个Proxy程序(可能是PHP,ASP,servlet等任何服务端程序),域A的页面JS直接调用本域下的Proxy程序,proxy程序负责将请求发送给域B下的链接并获取到数据,最后再通过Proxy将数据返回给页面JS使用。代理转发基本的流程就如上面所说的那样,用网上的一张图看起来会更加直观一点。
使用代理proxy之后:
这种方案经过了中间Proxy,所以延迟可能稍微大一点,并且会加重本域服务器的负荷,开发工作量也稍微大一点。
雅虎开发者中心为我们提供了这样的一段代码,可以借过来参考一下:
<?php
// PHP Proxy example for Yahoo! Web services.
// Responds to both HTTP GET and POST requests
//
// Author: Jason Levitt
// December 7th, 2005
//
// Allowed hostname (api.local and api.travel are also possible here)
define ('HOSTNAME', 'http://search.yahooapis.com/');
// Get the REST call path from the AJAX application
// Is it a POST or a GET?
$path = ($_POST['yws_path']) ? $_POST['yws_path'] : $_GET['yws_path'];
$url = HOSTNAME.$path;//获取请求完整URL
// Open the Curl session
$session = curl_init($url);//初始化一个新的会话,返回一个cURL句柄
// If it's a POST, put the POST data in the body
if ($_POST['yws_path']) {
$postvars = '';
while ($element = current($_POST)) {
$postvars .= urlencode(key($_POST)).'='.urlencode($element).'&';
next($_POST);
}
curl_setopt ($session, CURLOPT_POST, true);
curl_setopt ($session, CURLOPT_POSTFIELDS, $postvars);
}
// Don't return HTTP headers. Do return the contents of the call
curl_setopt($session, CURLOPT_HEADER, false);
curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
// Make the call
$xml = curl_exec($session);
// The web service returns XML. Set the Content-Type appropriately
header("Content-Type: text/xml");
echo $xml;
curl_close($session);
?>
可以根据它的这段代码区修改然后实现自己的需要,比如我按照这个模版修改后得到了自己的代理服务器的代码。
3.JSONP。
JSONP是JSON with Padding的略称。它是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问(这仅仅是JSONP简单的实现形式)<script>标签的src属性并不被同源策略所约束,所以可以获取任何服务器上脚本并执行。
跨域的方法还有几种,至于选择哪一种,首先要看当前面临的跨域的类别,是哪一种跨域类型,哪一种解决方法适合它,然后再根据自己的习惯来选择囖~