跨域AJAX

来源:互联网 发布:java kindle 百度云 编辑:程序博客网 时间:2024/05/20 11:26

跨域AJAX

由于浏览器存在同源策略机制,同源策略阻止从一个源加载的文档或脚本获取或设置另一个源加载的文档的属性。

特别的:由于同源策略是浏览器的限制,所以请求的发送和响应是可以进行,只不过浏览器不接受罢了。

浏览器同源策略并不是对所有的请求均制约:

  • 制约: XmlHttpRequest
  • 不叼: img、iframe、script等具有src属性的标签

跨域,跨域名访问,如:http://www.c1.com 域名向 http://www.c2.com域名发送请求。

1、JSONP实现跨域请求

JSONP(JSONP - JSON with Padding是JSON的一种“使用模式”),利用script标签的src属性(浏览器允许script标签跨域)

复制代码
<!DOCTYPE html><html><head lang="en">    <meta charset="UTF-8">    <title></title></head><body>    <p>        <input type="button" onclick="Jsonp1();"  value='提交'/>    </p>    <p>        <input type="button" onclick="Jsonp2();" value='提交'/>    </p>    <script type="text/javascript" src="jquery-1.12.4.js"></script>    <script>        function Jsonp1(){            var tag = document.createElement('script');            tag.src = "http://c2.com:8000/test/";            document.head.appendChild(tag);            document.head.removeChild(tag);        }        function Jsonp2(){            $.ajax({                url: "http://c2.com:8000/test/",                type: 'GET',                dataType: 'JSONP',                success: function(data, statusText, xmlHttpRequest){                    console.log(data);                }            })        }    </script></body></html>
复制代码

下载:http://files.cnblogs.com/files/wupeiqi/ajax_demo.zip
复制代码
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title></title></head><body><input type="button" onclick="AjaxRequest()" value="跨域Ajax" /><div id="container"></div><script src="jquery-1.8.2.min.js" type="text/javascript"></script>    <script type="text/javascript">        function AjaxRequest() {            $.ajax({                url: 'http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403',                type: 'GET',                dataType: 'jsonp',                jsonp: 'callback',                jsonpCallback: 'list',                success: function (data) {                    $.each(data.data,function(i){                        var item = data.data[i];                        var str = "<p>"+ item.week +"</p>";                        $('#container').append(str);                        $.each(item.list,function(j){                            var temp = "<a href='" + item.list[j].link +"'>" + item.list[j].name +" </a><br/>";                            $('#container').append(temp);                        });                        $('#container').append("<hr/>");                    })                }            });        }</script></body></html>
复制代码



2、CORS

随着技术的发展,现在的浏览器可以支持主动设置从而允许跨域请求,即:跨域资源共享(CORS,Cross-Origin Resource Sharing),其本质是设置响应头,使得浏览器允许跨域请求。

* 简单请求 OR 非简单请求

1
2
3
4
5
6
7
8
9
10
11
12
13
条件:
    1、请求方式:HEAD、GET、POST
    2、请求头信息:
        Accept
        Accept-Language
        Content-Language
        Last-Event-ID
        Content-Type 对应的值是以下三个中的任意一个
                                application/x-www-form-urlencoded
                                multipart/form-data
                                text/plain
 
注意:同时满足以上两个条件时,则是简单请求,否则为复杂请求

* 简单请求和非简单请求的区别?

1
2
   简单请求:一次请求
非简单请求:两次请求,在发送数据之前会先发一次请求用于做“预检”,只有“预检”通过后才再发送一次请求用于数据传输。

* 关于“预检”

1
2
3
4
5
6
7
- 请求方式:OPTIONS
- “预检”其实做检查,检查如果通过则允许传输数据,检查不通过则不再发送真正想要发送的消息
- 如何“预检”
     => 如果复杂请求是PUT等请求,则服务端需要设置允许某请求,否则“预检”不通过
        Access-Control-Request-Method
     => 如果复杂请求设置了请求头,则服务端需要设置允许某请求头,否则“预检”不通过
        Access-Control-Request-Headers

 

基于cors实现AJAX请求:

a、支持跨域,简单请求

服务器设置响应头:Access-Control-Allow-Origin = '域名' 或 '*'

复制代码
<!DOCTYPE html><html><head lang="en">    <meta charset="UTF-8">    <title></title></head><body>    <p>        <input type="submit" onclick="XmlSendRequest();" />    </p>    <p>        <input type="submit" onclick="JqSendRequest();" />    </p>    <script type="text/javascript" src="jquery-1.12.4.js"></script>    <script>        function XmlSendRequest(){            var xhr = new XMLHttpRequest();            xhr.onreadystatechange = function(){                if(xhr.readyState == 4) {                    var result = xhr.responseText;                    console.log(result);                }            };            xhr.open('GET', "http://c2.com:8000/test/", true);            xhr.send();        }        function JqSendRequest(){            $.ajax({                url: "http://c2.com:8000/test/",                type: 'GET',                dataType: 'text',                success: function(data, statusText, xmlHttpRequest){                    console.log(data);                }            })        }    </script></body></html>
复制代码
class MainHandler(tornado.web.RequestHandler):    def get(self):        self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")        self.write('{"status": true, "data": "seven"}')

b、支持跨域,复杂请求

由于复杂请求时,首先会发送“预检”请求,如果“预检”成功,则发送真实数据。

  • “预检”请求时,允许请求方式则需服务器设置响应头:Access-Control-Request-Method
  • “预检”请求时,允许请求头则需服务器设置响应头:Access-Control-Request-Headers
  • “预检”缓存时间,服务器设置响应头:Access-Control-Max-Age
复制代码
<!DOCTYPE html><html><head lang="en">    <meta charset="UTF-8">    <title></title></head><body>    <p>        <input type="submit" onclick="XmlSendRequest();" />    </p>    <p>        <input type="submit" onclick="JqSendRequest();" />    </p>    <script type="text/javascript" src="jquery-1.12.4.js"></script>    <script>        function XmlSendRequest(){            var xhr = new XMLHttpRequest();            xhr.onreadystatechange = function(){                if(xhr.readyState == 4) {                    var result = xhr.responseText;                    console.log(result);                }            };            xhr.open('PUT', "http://c2.com:8000/test/", true);            xhr.setRequestHeader('k1', 'v1');            xhr.send();        }        function JqSendRequest(){            $.ajax({                url: "http://c2.com:8000/test/",                type: 'PUT',                dataType: 'text',                headers: {'k1': 'v1'},                success: function(data, statusText, xmlHttpRequest){                    console.log(data);                }            })        }    </script></body></html>
复制代码
复制代码
class MainHandler(tornado.web.RequestHandler):        def put(self):        self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")        self.write('{"status": true, "data": "seven"}')    def options(self, *args, **kwargs):        self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")        self.set_header('Access-Control-Allow-Headers', "k1,k2")        self.set_header('Access-Control-Allow-Methods', "PUT,DELETE")        self.set_header('Access-Control-Max-Age', 10)
复制代码

c、跨域获取响应头

默认获取到的所有响应头只有基本信息,如果想要获取自定义的响应头,则需要再服务器端设置Access-Control-Expose-Headers。

复制代码
<!DOCTYPE html><html><head lang="en">    <meta charset="UTF-8">    <title></title></head><body>    <p>        <input type="submit" onclick="XmlSendRequest();" />    </p>    <p>        <input type="submit" onclick="JqSendRequest();" />    </p>    <script type="text/javascript" src="jquery-1.12.4.js"></script>    <script>        function XmlSendRequest(){            var xhr = new XMLHttpRequest();            xhr.onreadystatechange = function(){                if(xhr.readyState == 4) {                    var result = xhr.responseText;                    console.log(result);                    // 获取响应头                    console.log(xhr.getAllResponseHeaders());                }            };            xhr.open('PUT', "http://c2.com:8000/test/", true);            xhr.setRequestHeader('k1', 'v1');            xhr.send();        }        function JqSendRequest(){            $.ajax({                url: "http://c2.com:8000/test/",                type: 'PUT',                dataType: 'text',                headers: {'k1': 'v1'},                success: function(data, statusText, xmlHttpRequest){                    console.log(data);                    // 获取响应头                    console.log(xmlHttpRequest.getAllResponseHeaders());                }            })        }    </script></body></html>
复制代码
复制代码
class MainHandler(tornado.web.RequestHandler):        def put(self):        self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")        self.set_header('xxoo', "seven")        self.set_header('bili', "daobidao")        self.set_header('Access-Control-Expose-Headers', "xxoo,bili")        self.write('{"status": true, "data": "seven"}')    def options(self, *args, **kwargs):        self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")        self.set_header('Access-Control-Allow-Headers', "k1,k2")        self.set_header('Access-Control-Allow-Methods', "PUT,DELETE")        self.set_header('Access-Control-Max-Age', 10)
复制代码

d、跨域传输cookie

在跨域请求中,默认情况下,HTTP Authentication信息,Cookie头以及用户的SSL证书无论在预检请求中或是在实际请求都是不会被发送。

如果想要发送:

  • 浏览器端:XMLHttpRequest的withCredentials为true
  • 服务器端:Access-Control-Allow-Credentials为true
  • 注意:服务器端响应的 Access-Control-Allow-Origin 不能是通配符 *
复制代码
<!DOCTYPE html><html><head lang="en">    <meta charset="UTF-8">    <title></title></head><body>    <p>        <input type="submit" onclick="XmlSendRequest();" />    </p>    <p>        <input type="submit" onclick="JqSendRequest();" />    </p>    <script type="text/javascript" src="jquery-1.12.4.js"></script>    <script>        function XmlSendRequest(){            var xhr = new XMLHttpRequest();            xhr.onreadystatechange = function(){                if(xhr.readyState == 4) {                    var result = xhr.responseText;                    console.log(result);                }            };            xhr.withCredentials = true;            xhr.open('PUT', "http://c2.com:8000/test/", true);            xhr.setRequestHeader('k1', 'v1');            xhr.send();        }        function JqSendRequest(){            $.ajax({                url: "http://c2.com:8000/test/",                type: 'PUT',                dataType: 'text',                headers: {'k1': 'v1'},                xhrFields:{withCredentials: true},                success: function(data, statusText, xmlHttpRequest){                    console.log(data);                }            })        }    </script></body></html>
复制代码
复制代码
class MainHandler(tornado.web.RequestHandler):        def put(self):        self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")        self.set_header('Access-Control-Allow-Credentials', "true")                self.set_header('xxoo', "seven")        self.set_header('bili', "daobidao")        self.set_header('Access-Control-Expose-Headers', "xxoo,bili")        self.set_cookie('kkkkk', 'vvvvv');        self.write('{"status": true, "data": "seven"}')    def options(self, *args, **kwargs):        self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com")        self.set_header('Access-Control-Allow-Headers', "k1,k2")        self.set_header('Access-Control-Allow-Methods', "PUT,DELETE")        self.set_header('Access-Control-Max-Age', 10)