php分享二十五:跨域请求

问题: 跨域请求有几种方式? jsonp支持哪几种请求方式? 支持post请求吗? 支持get请求吗?

由于浏览器同源策略,凡是发送请求url的协议、域名、端口三者之间任意一与当前页面地址不同即为跨域。具体可以查看下表:

方法一:JSONP

这种方式主要是通过动态插入一个script标签。浏览器对script的资源引用没有同源限制,同时资源加载到页面后会立即执行(没有阻塞的情况下)。

<script>
var _script = document.createElement("script");
_script.type = "text/javascript";
_script.src = "http://test.larvel.com/jsonp?callback=f";
document.head.appendChild(_script);
</script>

实际项目中JSONP通常用来获取json格式数据,这时前后端通常约定一个参数callback,该参数的值,就是处理返回数据的函数名称。

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
    <title>jsonp_test</title>

    <script>
      var f = function(data){
        alert(data.name);
      }
      /*var xhr = new XMLHttpRequest();
      xhr.onload = function(){
        alert(xhr.responseText);
      };
      xhr.open(‘POST‘, ‘http://localhost:8888/cors‘, true);
      xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
      xhr.send("f=json");*/
    </script>

    <script>
      var _script = document.createElement(‘script‘);
      _script.type = "text/javascript";
      _script.src = "http://localhost:8888/jsonp?callback=f";
      document.head.appendChild(_script);
    </script>
  </head>
var query = _url.query;
        console.log(query);
        var params = qs.parse(query);
        console.log(params);
        var f = "";

        f = params.callback;

        res.writeHead(200, {"Content-Type": "text/javascript"});
        res.write(f + "({name:‘hello world‘})");
        res.end();

  缺点:

  1、这种方式无法发送post请求(这里

  2、另外要确定jsonp的请求是否失败并不容易,大多数框架的实现都是结合超时时间来判定。

方法二:Proxy代理

这种方式首先将请求发送给后台服务器,通过服务器来发送请求,然后将请求的结果传递给前端。

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
    <title>proxy_test</title>

    <script>
      var f = function(data){
        alert(data.name);
      }
      var xhr = new XMLHttpRequest();
      xhr.onload = function(){
        alert(xhr.responseText);
      };
      xhr.open(‘POST‘, ‘http://localhost:8888/proxy?http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer‘, true);
      xhr.send("f=json");
    </script>
  </head>

  <body>
  </body>
</html>
var proxyUrl = "";
      if (req.url.indexOf(‘?‘) > -1) {
          proxyUrl = req.url.substr(req.url.indexOf(‘?‘) + 1);
          console.log(proxyUrl);
      }
      if (req.method === ‘GET‘) {
          request.get(proxyUrl).pipe(res);
      } else if (req.method === ‘POST‘) {
          var post = ‘‘;     //定义了一个post变量,用于暂存请求体的信息

        req.on(‘data‘, function(chunk){    //通过req的data事件监听函数,每当接受到请求体的数据,就累加到post变量中
            post += chunk;
        });

        req.on(‘end‘, function(){    //在end事件触发后,通过querystring.parse将post解析为真正的POST请求格式,然后向客户端返回。
            post = qs.parse(post);
            request({
                      method: ‘POST‘,
                      url: proxyUrl,
                      form: post
                  }).pipe(res);
        });
      }

需要注意的是如果你代理的是https协议的请求,那么你的proxy首先需要信任该证书(尤其是自定义证书)或者忽略证书检查,否则你的请求无法成功。12306就提供了一个鲜活的例子。

还需要注意一点,对于同一请求浏览器通常会从缓存中读取数据,我们有时候不想从缓存中读取,所以会加一个preventCache参数,这个时候请求 url变成:url?preventCache=12345567....;这本身没有什么问题,问题出在当使用某些前端框架(比如jquery)发送 proxy代理请求时,请求url为proxy?url,同时设置preventCache:true,框架不能正确处理这个参数,结果发出去的请求变成 proxy?url&preventCache=123456(正长应为proxy?url?preventCache=12356);后端截取 后发送的请求为url&preventCache=123456,根本没有这个地址,所以你得不到正确结果。

方法三:CORS

这是现代浏览器支持跨域资源请求的一种方式。

当你使用XMLHttpRequest发送请求时,浏览器发现该请求不符合同源策略,会给该请求加一个请求头:Origin,后台进行一系列处理,如果确 定接受请求则在返回结果中加入一个响应头:Access-Control-Allow-Origin;浏览器判断该相应头中是否包含Origin的值,如 果有则浏览器会处理响应,我们就可以拿到响应数据,如果不包含浏览器直接驳回,这时我们无法拿到响应数据。

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
    <title>jsonp_test</title>

    <script>
      /*var f = function(data){
        alert(data.name);
      }*/
      var xhr = new XMLHttpRequest();
      xhr.onload = function(){
        alert(xhr.responseText);
      };
      xhr.open(‘POST‘, ‘http://localhost:8888/cors‘, true);
      xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
      xhr.send("f=json");
    </script>

    <script>
     /* var _script = document.createElement(‘script‘);
      _script.type = "text/javascript";
      _script.src = "http://localhost:8888/jsonp?callback=f";
      document.head.appendChild(_script);*/
    </script>
  </head>

  <body>
  </body>
</html>

前端cors
if (req.headers.origin) {

            res.writeHead(200, {
                "Content-Type": "text/html; charset=UTF-8",
                "Access-Control-Allow-Origin":‘http://localhost‘/*,
                ‘Access-Control-Allow-Methods‘: ‘GET, POST, OPTIONS‘,
                ‘Access-Control-Allow-Headers‘: ‘X-Requested-With, Content-Type‘*/
            });
            res.write(‘cors‘);
            res.end();
        }

匹配

如果我们把Access-Control-Allow-Origin去掉,浏览器会驳回响应,我们也就拿不到数据。

需要注意的一点是Preflighted Request的透明服务器验证机制支持开发人员使用自定义的头部、GET或POST之外的方法,以及不同类型的主题内容。总结如如:

  1、非GET 、POST请求

  2、POST请求的content-type不是常规的三个:application/x- www-form-urlencoded(使用 HTTP 的 POST 方法提交的表单)、multipart/form-data(同上,但主要用于表单提交时伴随文件上传的场合)、text/plain(纯文本)

  3、POST请求的payload为text/html

  4、设置自定义头部

  OPTIONS请求头部中会包含以下头部:Origin、Access-Control-Request-Method、Access-Control-Request-Headers,发送这个请求后,服务器可以设置如下头部与浏览器沟通来判断是否允许这个请求。

  Access-Control-Allow-Origin、Access-Control-Allow-Method、Access-Control-Allow-Headers

var xhr = new XMLHttpRequest();
      xhr.onload = function(){
        alert(xhr.responseText);
      };
      xhr.open(‘POST‘, ‘http://localhost:8888/cors‘, true);
      xhr.setRequestHeader("Content-Type", "text/html");
      xhr.send("f=json");
if (req.headers.origin) {

            res.writeHead(200, {
                "Content-Type": "text/html; charset=UTF-8",
                "Access-Control-Allow-Origin":‘http://localhost‘,
                ‘Access-Control-Allow-Methods‘: ‘GET,POST,OPTIONS‘,
                ‘Access-Control-Allow-Headers‘: ‘X-Requested-With, Content-Type‘/**/
            });
            res.write(‘cors‘);
            res.end();
        }

  通过setRequestHeader(‘X-Request-With‘, null)可以避免浏览器发送OPTIONS请求。

  根据我的测试,当使用cors发送跨域请求时失败时,后台是接收到了这次请求,后台可能也执行了数据查询操作,只是响应头部不合符要求,浏览器阻断了这次请求。

方法四:XDR

  这是IE8、IE9提供的一种跨域解决方案,功能较弱只支持get跟post请求,而且对于协议不同的跨域是无能为力的,比如在http协议下发送https请求。看一下微软自己的例子就行

<!DOCTYPE html>

<html>
<body>
  <h2>XDomainRequest</h2>
  <input type="text" id="tbURL" value="http://www.contoso.com/xdr.txt" style="width: 300px"><br>
  <input type="text" id="tbTO" value="10000"><br>
  <input type="button" onclick="mytest()" value="Get">   
    <input type="button" onclick="stopdata()" value="Stop">   
    <input type="button" onclick="readdata()" value="Read">
  <br>
  <div id="dResponse"></div>
  <script>
    var xdr;
    function readdata()
    {
      var dRes = document.getElementById(‘dResponse‘);
      dRes.innerText = xdr.responseText;
      alert("Content-type: " + xdr.contentType);
      alert("Length: " + xdr.responseText.length);
    }

    function err()
    {
      alert("XDR onerror");
    }

    function timeo()
    {
      alert("XDR ontimeout");
    }

    function loadd()
    {
      alert("XDR onload");
      alert("Got: " + xdr.responseText);
    }

    function progres()
    {
      alert("XDR onprogress");
      alert("Got: " + xdr.responseText);
    }

    function stopdata()
    {
      xdr.abort();
    }

    function mytest()
    {
      var url = document.getElementById(‘tbURL‘);
      var timeout = document.getElementById(‘tbTO‘);
      if (window.XDomainRequest)
      {
        xdr = new XDomainRequest();
        if (xdr)
        {
          xdr.onerror = err;
          xdr.ontimeout = timeo;
          xdr.onprogress = progres;
          xdr.onload = loadd;
          xdr.timeout = tbTO.value;
          xdr.open("get", tbURL.value);
          xdr.send();
        }
        else
        {
          alert("Failed to create");
        }
      }
      else
      {
        alert("XDR doesn‘t exist");
      }
    }
  </script>
</body>
</html>

以上就是我在实际项目中遇到的跨域请求资源的情况,有一种跨域需要特别注意就是在https协议下发送https请求,除了使用proxy代理外其他方法都无解,会被浏览器直接block掉。如果哪位道友知道解决方法,麻烦你告诉我一声。

  最后附上完整的测试demo

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
    <title>jsonp_test</title>

    <script>
      /*var f = function(data){
        alert(data.name);
      }*/
      var xhr = new XMLHttpRequest();
      xhr.onload = function(){
        alert(xhr.responseText);
      };
      xhr.open(‘POST‘, ‘http://localhost:8888/cors‘, true);
      xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
      xhr.setRequestHeader("aaaa","b");
      xhr.send("f=json");
    </script>

    <script>
     /* var _script = document.createElement(‘script‘);
      _script.type = "text/javascript";
      _script.src = "http://localhost:8888/jsonp?callback=f";
      document.head.appendChild(_script);*/
    </script>
  </head>

  <body>
  </body>
</html>
<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
    <title>proxy_test</title>

    <script>
      var f = function(data){
        alert(data.name);
      }
      var xhr = new XMLHttpRequest();
      xhr.onload = function(){
        alert(xhr.responseText);
      };
      xhr.open(‘POST‘, ‘http://localhost:8888/proxy?https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer‘, true);
      xhr.send("f=json");
    </script>
  </head>

  <body>
  </body>
</html>

node-server

var http = require(‘http‘);
var url = require(‘url‘);
var fs = require(‘fs‘);
var qs = require(‘querystring‘);
var request = require(‘request‘);

http.createServer(function(req, res){
    var _url = url.parse(req.url);
    if (_url.pathname === ‘/jsonp‘) {
        var query = _url.query;
        console.log(query);
        var params = qs.parse(query);
        console.log(params);
        var f = "";

        f = params.callback;

        res.writeHead(200, {"Content-Type": "text/javascript"});
        res.write(f + "({name:‘hello world‘})");
        res.end();
    } else if (_url.pathname === ‘/proxy‘) {
      var proxyUrl = "";
      if (req.url.indexOf(‘?‘) > -1) {
          proxyUrl = req.url.substr(req.url.indexOf(‘?‘) + 1);
          console.log(proxyUrl);
      }
      if (req.method === ‘GET‘) {
          request.get(proxyUrl).pipe(res);
      } else if (req.method === ‘POST‘) {
          var post = ‘‘;     //定义了一个post变量,用于暂存请求体的信息

        req.on(‘data‘, function(chunk){    //通过req的data事件监听函数,每当接受到请求体的数据,就累加到post变量中
            post += chunk;
        });

        req.on(‘end‘, function(){    //在end事件触发后,通过querystring.parse将post解析为真正的POST请求格式,然后向客户端返回。
            post = qs.parse(post);
            request({
                      method: ‘POST‘,
                      url: proxyUrl,
                      form: post
                  }).pipe(res);
        });
      }
    } else if (_url.pathname === ‘/index‘) {
        fs.readFile(‘./index.html‘, function(err, data) {
          res.writeHead(200, {"Content-Type": "text/html; charset=UTF-8"});
            res.write(data);
            res.end();
        });
    } else if (_url.pathname === ‘/cors‘) {
        if (req.headers.origin) {

            res.writeHead(200, {
                "Content-Type": "text/html; charset=UTF-8",
                "Access-Control-Allow-Origin":‘http://localhost‘,
                ‘Access-Control-Allow-Methods‘: ‘GET,POST,OPTIONS‘,
                ‘Access-Control-Allow-Headers‘: ‘X-Requested-With, Content-Type,aaaa‘/**/
            });
            res.write(‘cors‘);
            res.end();
        }
    }

}).listen(8888);

参考:http://www.cnblogs.com/dojo-lzz/p/4265637.html

时间: 2024-08-03 19:19:26

php分享二十五:跨域请求的相关文章

CORS ajax跨域请求php简单完整案例一则

一.CORS: Cross-Origin Resource Sharing CORS是Cross-Origin Resource Sharing的缩写,表示跨域的资源分享,不仅可以跨子域,就算域名长得完全不一样,也可以进行资源获取. 比较常见的应用之一就是Ajax跨域请求数据. 这个特性IE11开始支持: 和股市一样,大好河山一片绿,青青草原漫无边. 二.ajax跨域请求的header设置和案例 和传统ajax请求相比,ajax跨域请求的偶尔工作量主要在数据接收方那一端,也就是在服务器端设置.

JS的jsonp是什么?5分钟学会jsonp跨域请求

一.jsonp是什么? jsonp是解决跨域请求的一种技术.浏览器为了防止CSRF攻击会采用同源策略(协议/主机/端口均相同)限制,对非同源发起http请求(即跨域请求)会被浏览器阻止. 二.jsonp跨域请求的原理? script标签的src属性不受同源策略限制,用此方式对非同源服务器请求资源,返回的JS代码会调用指定的函数,携带的参数就是所需的数据,这样就完成了跨域请求. 三.原生JS的jsonp跨域请求: 首先声明一个处理返回数据的函数,返回的JS代码会调用此函数: function do

angular学习笔记(二十五)-$http(3)-转换请求和响应格式

本篇主要讲解$http(config)的config中的tranformRequest项和transformResponse项 1. transformRequest: $http({ transformRequest: function(data){ //对前台发送的data进行处理 return data } }) 这个在测试的时候遇到了很大的问题.只要经过transformRequest函数处理,哪怕是不做任何处理,node后台都会报错,需要尝试使用php 2. transformResp

第114天:Ajax跨域请求解决方法(二)

一.什么是跨域 我们先回顾一下域名地址的组成: http:// www . google : 8080 / script/jquery.js   http:// (协议号) www  (子域名) google (主域名) 8080 (端口号) script/jquery.js (请求的地址) * 当协议.子域名.主域名.端口号中任意一各不相同时,都算不同的"域". * 不同的域之间相互请求资源,就叫"跨域". 比如:http://www.abc.com/index.

vue开发之跨域请求,请求头not allowed by Access-Control-Allow-Headers,后端cookie session值取不到(二)

原因:你本地的请求ajax的get和post请求:如果你的请求头内放一些可用验证数据Token的时候就会存在跨域请求这是浏览器所不允许的问题: 方案一:后台的接口请求模式都写成jsonp请求,前端去调用: 特点:是一种非正式传输协议,该协议的一个要点就是允许用户传递一个callback 或者开始就定义一个回调方法,参数给服务端,然后服务端返回数据时会将这个callback 参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了. 缺点:它只支持GET请求而不支

AJAX(XMLHttpRequest)进行跨域请求方法详解(二)

注意:以下代码请在Firefox 3.5.Chrome 3.0.Safari 4之后的版本中进行测试.IE8的实现方法与其他浏览不同. 2,预检请求 预检请求首先需要向另外一个域名的资源发送一个 HTTP OPTIONS 请求头,其目的就是为了判断实际发送的请求是否是安全的.下面的2种情况需要进行预检:a,不是上面的简单请求,比如使用Content-Type 为 application/xml 或 text/xml 的 POST 请求b,在请求中设置自定义头,比如 X-JSON.X-MENGXI

原生JS实现Ajax及Ajax的跨域请求

  前  言          如今,从事前端方面的程序猿们,如果,不懂一些前后台的数据交互方面的知识的话,估计都不太好意思说自己是程序猿.当然,如今有着许多的框架,都有相对应的前后台数据交互的方法. 而,其中,用得最多的应该苏算是JQuery的Ajax了.但是,今天,影子向大家介绍的是原生js的Ajax,及跨域请求. 一. JQuery的Ajax 首先,先回忆下JQuery的Ajax写法: $.ajax({ url: , type: '', dataType: '', data: { }, s

前端跨域请求原理及实践

前端跨域请求原理及实践 2017-03-03 前端大全 (点击上方公众号,可快速关注) 作者:高鹏 tingandpeng.com/2016/09/05/前端跨域请求原理及实践/ 如有好文章投稿,请点击 → 这里了解详情 一. 跨域请求的含义 浏览器的同源策略,出于防范跨站脚本的攻击,禁止客户端脚本(如 JavaScript)对不同域的服务进行跨站调用. 一般的,只要网站的 协议名protocol. 主机host. 端口号port 这三个中的任意一个不同,网站间的数据请求与传输便构成了跨域调用.

AJAX请求和跨域请求详解(原生JS、Jquery)

一.概述 AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术. AJAX = 异步 JavaScript 和 XML,是一种用于创建快速动态网页的技术.通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新.这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新.传统的网页(不使用 AJAX)如果需要更新内容,必需重载整个网页面. 本博客实验环境: python:2.7.11 web框架:tonado jquery:2.1.1 二.“伪”AJAX 由于