Ajax跨域请求

Posted 明王不动心

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Ajax跨域请求相关的知识,希望对你有一定的参考价值。

一、同源策略

同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,

如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。

可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。

同源策略,它是由Netscape提出的一个著名的安全策略。现在所有支持javascript 的浏览器都会使用这个策略。

所谓同源是指,域名,协议,端口相同。当一个浏览器的两个tab页中分别打开来 百度和谷歌的页面当浏览器的百度tab页执行一个脚本的时候会检查这个脚本是属于哪个页面的,

即检查是否同源,只有和百度同源的脚本才会被执行,如果非同源,那么在请求数据时,浏览器会在控制台中报一个异常,提示拒绝访问。
 
在下面的实例中,通过Ajax访问自己的页面没有问题:
实例:
前端代码
后端代码

结果:

 

 

二、跨域

所谓的跨域就是请求的并不是本地url,具体实例请看:

 现在在项目1通过ajax访问项目2的页面(8001访问8002):

点击按钮发现并没有返回我们希望看到的,那到底是哪一步出现了问题了:

在项目2的后台,我们看到:

证明了已经处理了,难道是接收被拦截了,在火狐查看前端页面:

问题很明显就是被拦截了,为什么被拦截了?我只能说这是一种安全措施,这是在浏览器设计之初就已经规定好的,一直延续至今。

 

三、跨域的解决方法

在实际工作中,由于在大互联网时代,各行各业分工十分细化,单就大数据而言,

有些公司专门做数据收集、有些公司只做数据处理、而有些只做销售,这些公司传输数据的手段就是跨域请求。

下面会讲解三种解决跨域的方法:

1.借助script标签实现跨域

我们常用的Jquery可以这样:

<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>

在项目启动进行加载的时候,就会去对应的服务器取数据,利用这种特性可以实现跨域请求:

返回一个func(),这样在前端:

最后就能打印其中的数据了。

如果把需要传递的数据放在括号里面,就能把它取出来了,这样就可以达到跨域请求的目的了。

为了达到数据的丰富性,我们可以先进行序列化。

最后实现的代码详解:

前端代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Title</title>
    <script src="/static/jquery-3.2.1.min.js"></script>
</head>
<body>
<h3>这是项目1</h3>
<button class="b1">send a ajax</button>

{% csrf_token %}

<script>
    function func(s) {
        console.log(s)
    }
    
    function cross_domain(url) {
{#        定义一个标签,添加一个url元素,将其添加到body里面#}
{#        为了不每次点击都会加载一个script标签,每次加载之后就删除#}
        var $ele_script = $("<script>");
        $ele_script.attr("src",url);
        $ele_script.attr("class","cs");
        $("body").append($ele_script);
        $(".cs").remove()
    }

{#    点击按钮的时候就会触发,此时才会加载<script>#}
{#    使用callback=func可以将后端传输字符串进行解耦,在后端可以接收callback,这样再传递func()到前端#}
    $(".b1").click(function () {
        cross_domain("http://127.0.0.1:8002/ajax_send/?callback=func")
    })

</script>
</body>
</html>

后端代码:

from django.shortcuts import render,HttpResponse

def index(request):

    return render(request,"index.html")

import json
def ajax_send(request):
    dict = {"name":"kebi"}
    func =request.GET.get("callback")  #这样可以不用固定函数名
    return  HttpResponse("%s(%s)"%(func,json.dumps(dict)))

这其实就是JSONP的简单实现模式,或者说是JSONP的原型:创建一个回调函数,

然后在远程服务上调用这个函数并且将JSON 数据形式作为参数传递,完成回调。

jsonp是json用来跨域的一个东西。原理是通过script标签的跨域特性来绕过同源策略。

将JSON数据填充进回调函数,这就是JSONP的JSON+Padding的含义。

一般情况下,我们希望这个script标签能够动态的调用,而不是像上面因为固定在html里面所以没等页面显示就执行了,很不灵活。

我们可以通过javascript动态的创建script标签,这样我们就可以灵活调用远程服务了。

 

2.jQuery对JSONP的实现

(1)getJSON

jQuery框架也当然支持JSONP,可以使用$.getJSON(url,[data],[callback])方法:

项目一前端部分:

<script>
    $(".b1").click(function () {
        $.getJSON("http://127.0.0.1:8002/ajax_send/?callback=?",function (data) {
{#            callback=?这个值系统会帮你随机生成,就相当于让面的ross_domain#}
{#            当拿到结果之后,只会执行function ()这个匿名函数#}
            console.log(data)
        })
    })
</script>

 

项目二后端部分:

import json
def ajax_send(request):
    dict = {"name":"kebi"}
    func =request.GET.get("callback")
    print("func",func)  #func jQuery3210924015436172589_1519900847362
    print("项目2.。。")
    return  HttpResponse("%s(%s)"%(func,json.dumps(dict)))

经过测试可以知道,这种方法也是可以的,其实就是对script的封装。

结果是一样的,要注意的是在url的后面必须添加一个callback参数,这样getJSON方法才会知道是用JSONP方式去访问服务,

callback后面的那个问号是内部自动生成的一个回调函数名。

此外,如果说我们想指定自己的回调函数名,或者说服务上规定了固定回调函数名该怎么办呢?我们可以使用$.ajax方法来实现

(2)$.ajax

看到这个有些人就疑惑,这个不就是Ajax吗,不是说ajax不行吗,这咋就又行了?

其实确实不行,只是Jquery的作者让它和ajax同名而已。

项目一前端:

<script>
$(".b1").click(function () {

   $.ajax({
       url:\'http://127.0.0.1:8002/ajax_send/\',
       dataType:"jsonp",   {# 期待数据类型,一定要加,只要有这句话,就会去添加script标签 #}
       jsonp: \'callback\',  {# 其实就是补充在后面:http://127.0.0.1:8002/ajax_send/?callback=SayHi#}
       jsonpCallback:"SayHi"  {# 如果这里不加jsonpCallback,就会是callback=?,这样就是getJson #}
   });
});

function SayHi(data) {
    console.log(data)
}
</script>

项目二后端:

def ajax_send(request):
    dict = {"name":"kebi"}
    func =request.GET.get("callback")
    print("func",func)  #func SayHi
    print("项目2.。。")
    return  HttpResponse("%s(%s)"%(func,json.dumps(dict)))

当然,最简单的形式还是通过回调函数来处理(推荐):

<script>
$(".b1").click(function () {

   $.ajax({
       url:\'http://127.0.0.1:8002/ajax_send/\',
       dataType:"jsonp",   
       jsonp: \'callback\', 
       success:function (data) {
           console.log(data)
       }
   });
});
</script>

 jsonp: \'callbacks\'就是定义一个存放回调函数的键,jsonpCallback是前端定义好的回调函数方法名\'SayHi\',

server端接受callback键对应值后就可以在其中填充数据打包返回了; 

jsonpCallback参数可以不定义,jquery会自动定义一个随机名发过去,那前端就得用回调函数来处理对应数据了。

利用jQuery可以很方便的实现JSONP来进行跨域访问。

  

注意:JSONP一定是GET请求

 

最后来一个跨域请求的实例:

<input type="button" onclick="AjaxRequest()" value="跨域Ajax" />


<div id="container"></div>


    <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>
跨域请求

以上是关于Ajax跨域请求的主要内容,如果未能解决你的问题,请参考以下文章

前端Jquery-Ajax跨域请求,并携带cookie

简单ajax跨域请求

ajax跨域请求

JQuery - Ajax和Tomcat跨域请求问题解决方法!

跨域 jquery ajax 请求

PHP中运用jQuery的Ajax跨域调用实现代码