Ajax前戏之json:

1、什么是json?

JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式。

 

2、json对象和JavaScript对象的关系

json对象:JavaScript对象的子集,json继承了JavaScript的number,string(" "),bool,null,array,{"name":"egon" ,"age ":18} 注意json只支持双引号 

 

3、json对象和json字符串的关系: 

json字符串就是json对象+引号的字符串化,‘json对象  ’,json对象=JS对象,json字符串‘ 里面’存储的JavaScript的数据类型,所以相比其他语言JavaScript把json字符串解析成JS对象有天然优势;

 

3、json字符串和Python的关系

Python有Python的数据类型,JS有JS的数据类型,但前后端之所以可以交互,是因为中间有 json字符串做中间转换;

 

 

   

合格的json对象:

["one", "two", "three"]

{ "one": 1, "two": 2, "three": 3 }

{"names": ["张三", "李四"] }

[ { "name": "张三"}, {"name": "李四"} ]
View Code

不合格的json对象

{ name: "张三", 'age': 32 }                     // 属性名必须使用双引号

[32, 64, 128, 0xFFF] // 不能使用十六进制值

{ "name": "张三", "age": undefined }            // 不能使用undefined

{ "name": "张三",
  "birthday": new Date('Fri, 26 Aug 2011 07:13:10 GMT'),
  "getName":  function() {return this.name;}    // 不能使用函数和日期对象
}
View Code

 

4、JavaScript的JSON.stringify()和JSON.stringify()方法

JSON.stringify(JS对象)     将JS对象序列化成 JSON字符串    ------->python的json.dumps()

<script>
{#JSON.stringify(JS对象) 将JS对象序列化成 JSON字符串#}
    console.log(typeof JSON.stringify([1,2,2,2]))
    console.log(typeof JSON.stringify({'name':'egon'}))
</script>
View Code

JSON.parse('JSON对象')    将json字符串反序列化成 JS对象--------->python的json.loads()

<script>
{#    JSON.parse('JSON对象')   将json字符串反序列化成 JS对象    #}
    console.log(JSON.parse('{"name":"egon","age":18}'))
    console.log(JSON.parse('[1,2,3,4,5]'))
</script>
View Code

 

5、json和XML的比较

 JSON 格式于2001年由 Douglas Crockford 提出,目的就是取代繁琐笨重的 XML数据交换格式。

 

用XML表示中国部分省市数据如下:

<?xml version="1.0" encoding="utf-8"?>
<country>
    <name>中国</name>
    <province>
        <name>黑龙江</name>
        <cities>
            <city>哈尔滨</city>
            <city>大庆</city>
        </cities>
    </province>
    <province>
        <name>广东</name>
        <cities>
            <city>广州</city>
            <city>深圳</city>
            <city>珠海</city>
        </cities>
    </province>
    <province>
        <name>台湾</name>
        <cities>
            <city>台北</city>
            <city>高雄</city>
        </cities>
    </province>
    <province>
        <name>新疆</name>
        <cities>
            <city>乌鲁木齐</city>
        </cities>
    </province>
</country>
View Code

用JSON表示如下:

{
    "name": "中国",
    "province": [{
        "name": "黑龙江",
        "cities": {
            "city": ["哈尔滨", "大庆"]
        }
    }, {
        "name": "广东",
        "cities": {
            "city": ["广州", "深圳", "珠海"]
        }
    }, {
        "name": "台湾",
        "cities": {
            "city": ["台北", "高雄"]
        }
    }, {
        "name": "新疆",
        "cities": {
            "city": ["乌鲁木齐"]
        }
    }]
View Code

 

优:

可以看到,JSON 简单的语法格式和清晰的层次结构明显要比 XML 容易阅读,并且在数据交换方面,由于 JSON 所使用的字符要比 XML 少得多,可以大大得节约传输数据所占用得带宽。

劣:

注意:

JSON格式取代了xml给网络传输带来了很大的便利,但是却没有了xml的一目了然,尤其是json数据很长的时候,我们会陷入繁琐复杂的数据节点查找中。
但是国人的一款在线工具 BeJson 、SoJson在线工具让众多程序员、新接触JSON格式的程序员更快的了解JSON的结构,更快的精确定位JSON格式错误

http://www.bejson.com/

 

6.把Python的datetime时间数据类型,转换成json字符串的方式

class DatetimeSerializer(json.JSONEncoder):
    """
    实现 date 和 datetime 类型的 JSON 序列化,以符合 公司数据格式要求。
    """

    def default(self, obj):
        if isinstance(obj, datetime.datetime):
            head_fmt = "%Y-%m-%d %H:%M:%S"
            return "{main_part}.{ms_part}".format(
                main_part=obj.strftime(head_fmt),
                ms_part=int(obj.microsecond / 1000))
        elif isinstance(obj, datetime.date):
            fmt = '%Y-%m-%d'
            return obj.strftime(fmt)
        return json.JSONEncoder.default(self, obj)
date 和 datetime 类型的 JSON 序列化
 def to_json(self, d):
        return json.dumps(d, cls=DatetimeSerializer)

 

 

 

 

 

 

Ajax是什么?

AJAXAsynchronous Javascript And XML)翻译成中文就是异步JavascriptXML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML,可以指定json),相对于Form表单而言的,提交时可以偷偷向后台发数据,页面不刷新;

 

2大特点:

1、和server端异步交互

2、偷偷向server端发送数据,页面

 

和form、a标签的区别

ajax、form、a标签都可以基于HTML页面向server端发送request,

但本质区别是form、a标签一般向server索要的是页面,而ajax则是字符串数据;

 

 

Jquery和Ajax关系:

Jquery没有Ajax功能,它之所以可以调用Ajax向服务端提交数据,是因为Jquey封装了原生Ajax的代码

使用原生Ajax的优势:

使用Ajax直接使用JS的XMLHttp Request对象, 无需引入Jquery了。这样响应客户端携带信息量减少,可节省流量。

 

一、Ajax种类

 

 0、在发送ajax之前初始化ajax设置, beforeSend 函数;(如何在发送ajax之前,做一些操作)

例如设置发送ajax需要携带的CSRF-TOCKEN

 function csrfSafeMethod(method) {
        // these HTTP methods do not require CSRF protection
        return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
    }
    $.ajaxSetup({
        beforeSend: function (xhr, settings) {
            // 请求头中设置一次csrf-token
            if(!csrfSafeMethod(settings.type)){
                xhr.setRequestHeader("X-CSRFToken", $.cookie('csrftoken'));
            }
        }
    });
View Code

 

1、jQueryAjax

不再过多赘述,就是jQuery框架封装了原生Ajax实现出来的;

<script>
    $('p button').click(function () {
      var $user=$('p input').val()
       d={
    "name": "中国",
    "province": [{
        "name": "黑龙江",
        "cities": {
            "city": ["哈尔滨", "大庆"]
        }
    }, {
        "name": "广东",
        "cities": {
            "city": ["广州", "深圳", "珠海"]
        }
    }, {
        "name": "台湾",
        "cities": {
            "city": ["台北", "高雄"]
        }
    }, {
        "name": "新疆",
        "cities": {
            "city": ["乌鲁木齐"]
        }
    }]
}
     d=JSON.stringify(d)
      $.ajax({
           url:'/ajax/',
           type:'POST',
{# traditional:一般是我们的data数据有数组时会用到 #}
           traditional:true,
           data:d,
{#  ----------------- ajax的回调函数----------------------#}
{#       1、server端response 200成功,执行的回调函数#}
           success:function (data) {
               data=JSON.parse(data)
               console.log(typeof data)},
{#      2、erver端 response错误,执行的回调函数 #}
           error:function () {
               console.log(arguments)
               alert(123) },
{#      3、无论server端返回的结果如何,都会执行的回调函数#}
           complete:function () {
               alert(321)  },
{#      4、根据server端返回的状态码,执行的回调函数#}
           statusCode:{
               '403':function () {alert(403)},
               '503':function () {alert(503)}

           }
          })
    })
</script>
View Code

 Django 响应错误状态码 

def Ajax(request):
    d=json.loads(request.body)
    print(d)
    province=d['province'][0]
    print(province)
    d={'city': ['哈尔滨', '大庆']}
    HttpResponse.status_code=503
    # return HttpResponse(json.dumps(d))
    return HttpResponse('OK')
View Code

 $.ajax参数

请求参数

data:
ajax请求要携带的数据是肯定是一个json的object对象,ajax方法就会默认地把它编码成urlencode (urlencoded:?a=1&b=2)就像form表单、a标签格式的数据发送给server,此外,ajax默认以get方式发送请求。


注意:因为ajax要携带的数据是json的object对象,也会默认编码成urlcode格式,思考 如果你用 requests模块或者原生ajax向server发送数据、或者发送json数据,应该怎么做?
当然要指定 数据content-Type 和报头信息?

#-----------------------------------------------------------------
processData:声明当前的data数据是否进行转码或预处理,默认为true,即预处理;if为false,
             那么对data:{a:1,b:2}会调用json对象的toString()方法,即{a:1,b:2}.toString()
             ,最后得到一个[object,Object]形式的结果。



#-----------------------------------------------------------------------



contentType:默认值: "application/x-www-form-urlencoded"。发送信息至服务器时内容编码类型。
             用来指明当前请求的数据编码格式;urlencoded:?a=1&b=2;如果想以其他方式提交数据,
             比如contentType:"application/json",即向服务器发送一个json字符串:
               $.ajax("/ajax_get",{
             
                  data:JSON.stringify({
                       a:22,
                       b:33
                   }),
                   contentType:"application/json",
                   type:"POST",
             
               });                          //{a: 22, b: 33}

             注意:contentType:"application/json"一旦设定,data必须是json字符串,不能是json




----------------------------------------------
traditional:一般是我们的data数据有数组时会用到 :data:{a:22,b:33,c:["x","y"]},
              traditional为false会对数据进行深层次迭代;
View Code

响应参数

/*

dataType:  预期服务器返回的数据类型,服务器端返回的数据会根据这个值解析后,传递给回调函数。
            默认不需要显性指定这个属性,ajax会根据服务器返回的content Type来进行转换;
            比如我们的服务器响应的content Type为json格式,这时ajax方法就会对响应的内容
            进行一个json格式的转换,if转换成功,我们在success的回调函数里就会得到一个json格式
            的对象;转换失败就会触发error这个回调函数。如果我们明确地指定目标类型,就可以使用
            data Type。
            dataType的可用值:html|xml|json|text|script
            见下dataType实例

*/
View Code

 

2.原生的ajax

Ajax主要就是使用 【XmlHttpRequest】对象来完成请求的操作,该对象在主流浏览器中均存在(除早起的IE),Ajax首次出现IE5.5中存在(ActiveX控件)。

XmlHttpRequest对象的主要方法:

XmlHttpRequest.open("请求方法","请求的url",是否执行回调函数?)

send用户发送请求

在请求体里

setRequestHead()
在请求头里设置数据


getRespnseHeaders()
获取所有响应头数据

getRespnseHeader(响应头)
获取响应头中指定得header对应值


abort 终止请求
View Code

XmlHttpRequest对象的属性:

bj.readyState XMLHttpResposr的状态

0:未初始化,尚未调用open方法
1:启动调用了open方法
2:发送已经调用了send方法
3:接收状态(已经接收了部分数据)
4:完成(接收完毕服务端响应的数据)


只要对象的ready State改变就会执行该函数
xhr.onreadystatechange=function () {
            
        }



obj.responseText 服务端返回的数据(字符串类型)
obj.responseXML 服务端返回的数据(XML对象)

obj.number states 服务端返回的状态码
obj.response stateText 服务端返回的状态信息
View Code

 

使用XmlHttpRequest对象发送 GET请求

    function add1() {
{#        得到一个XMLHttpRequest对象 xhr   #}
        var xhr=new XMLHttpRequest();
{#        open打开一个http连接到指定url   XMLHttpRequest请求#}
        xhr.open('get','/add1/?i1=18&name=张根 ')
          {#       设置请求体的数据#}
        xhr.send()
{#        XMLHttpRquest的状态改变这个函数的状态就会执行jquryAjax中的success回调函数就是基于此#}
        xhr.onreadystatechange=function () {
            if(xhr.readyState==1){console.log("对象未调用open方法")}
            if(xhr.readyState==2){console.log("请求发送")}
            if(xhr.readyState==3){console.log("接收中")}
            if (xhr.readyState == 4) {console.log(xhr.responseText)}}
    }
View Code

 

使用XmlHttpRequest对象发送 POST请求

function add1() {

var xhr= new XMLHttpRequest()
xhr.open('post','/add1/')
xhr.send('name=张根&age=12')
}
View Code

 

 问题出现了为什么后端request.post方法没有数据呢?

使用jQuery发送post请求jQuery会默认把 发送的数据(js对象)编码成urlencoded格式,使用原生ajax就不会了,

所以使用原生ajax发POST请求之前,请求头中 务必要指定数据的编码格式“Content-Type”, “application/x-www-form-urlencoded”才能发到server端;

function add1() {
var xhr= new XMLHttpRequest()
xhr.open('post','/add1/')
xhr.setRequestHeader("ConTent-Type" ,"application/x-www-form-urlencoded")
xhr.send('name=张根&age=12')
               }
View Code

 

 

 3、iframe标签+form表单伪造Ajax

 

所谓伪装Ajax操作就是不利于任何Ajax,利于其他技术向后台发送数据,这个其他的技术要从 iframa标签说起。。。。。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>欢迎来到乐X网</title>
</head>
<body>

<iframe style="width:1000px; height:2000px" 

src="https://www.hhh286.com/htm/movieplay1/6748.htm" ></iframe>

</body>
</html>
View Code

神奇的一幕发生了 自动跳转到其他网站了

还可以 这么玩

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>欢迎来到乐C网</title>
</head>
<body>
<div>
    <input type="text" id="txt1">
    <input type="button" value="查看" onclick="cheangurl()">
</div>
<iframe id="ifr" style="width:1000px; height:2000px" src="https://www.baidu.com" ></iframe>

</body>

<script>
   function cheangurl() {
   var inpu=document.getElementById('txt1').value
    document.getElementById('ifr').src=inpu
   }

</script>
</html>
View Code

 

玩了2把就得出结论了

1、iframe标签可以不刷新发送http请求特性

2、服务端返回什么值 就 iframe标签中就会显示什么

 

思考:form表单和 iframe标签配合起来不就可以伪造 ajax请求了!

<form action="/fakeajax/" method="post" target="ifr">
{#     target="ifr" taget目标靶子 表示From不直接把打包的input标签数据提交到后台,而是通过属性为 

ifr的iframe标签  #}
    <iframe name="ifr" style="display: none"></iframe>
    <input name="user" type="text">
    <input type="submit" value="提交">
</form>
View Code

 

 

form把数据提交给 iframe标签间接向服务端发送POST请求,既向后台发送了数据,页面也不会刷新,但是怎么模拟回调函数呢?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>伪造Ajax</title>
</head>
<body>

<input type="text">
<form action="/fakeajax/" method="post" target="ifr">
    <iframe name="ifr" style="display: block" onload="loadiframe()"></iframe>
{#    当iframe加载时,也就是有返回值的时候 执行loadiframe()     模拟回调函数#}
    <input name="user" type="text">
    <input type="submit" value="提交">
</form>
</body>
<script>
   function loadiframe() {
       alert('回来了')
   }
</script>
</html>
View Code

会报错因为 加载<iframe name="ifr" style="display: block" onload="loadiframe()"></iframe>第一次加载触发onload时间 但是JS代码还在下面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>伪造Ajax</title>
</head>
<body>

<input type="text">
<form id="f1" action="/fakeajax/" method="post" target="ifr">
    <iframe name="ifr" id="ifr"></iframe>
{#    当iframe加载时,也就是有返回值的时候 执行loadiframe()     模拟回调函数#}
    <input name="user" type="text">
    <a onclick="submit_form()">提交 </a>
</form>
</body>
<script>
    function submit_form() {
       document.getElementById('f1').submit()
       document.getElementById('ifr').onload=loadiframe
    }
   function loadiframe() {
       alert('回来了')
   }
</script>
</html>
View Code

 最终版

iframe标签中 值不是简单的文本而是又嵌套了一个页面,如何获取iframe标签中的值 ?

 

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>伪造Ajax</title>
</head>
<body>

<input type="text">
<form id="f1" action="/fakeajax/" method="post" target="ifr">
    <iframe name="ifr" id="ifr"></iframe>
{#    当iframe加载时,也就是有返回值的时候 执行loadiframe()     模拟回调函数#}
    <input name="user" type="text">
    <a onclick="submit_form()">提交 </a>
</form>
</body>
<script>
    function submit_form() {
       document.getElementById('f1').submit()
       document.getElementById('ifr').onload=loadiframe
    }
   function loadiframe() {
      var return_values=document.getElementById('ifr').contentWindow.document.body.innerHTML
      console.log(return_values)
   }
</script>
</html>
View Code

 

 

二、基于Ajax上传文件并预览

不管是原生ajax和jQuery都可以依赖JS中一个FormData对象上传文件

上面我们已经尝试过使用原生的ajax发送字符串数据,那怎么上传文件呢?且听 京西沙河淫王娓娓道来。。。。。。。

话说 想要使用原生的ajax要想发送文件,就必须借助JS中formdata对象,( var formdata=new FormData())

帮我们把文件 构造成特定的请求体和请求头,注意发送字符串时要自定义请求头中ConTent-Type,现在不用多此一举了;

 

1、原生的ajax

前端

!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>原生Aja上传文件</title>
</head>
<body>
<h1>原生ajax上传文件</h1>
<p><input type="file"  id="f1"></p>
<p><input id="f2" type="button" onclick="fileup()" value="上传"></p>
</body>
<script>
    function fileup(){
        var formdata=new FormData()
{#        要想发文件必须借助一个特殊的 formdata对象,帮助我们封装 文件对象 #}
        formdata.append('k1','v1')
        var xhr= new XMLHttpRequest()
        xhr.open('POST','/fileup/')
{#        xhr.setRequestHeader("ConTent-Type" ,"application/x-www-form-urlencoded")#}
{#        切记 既然文件对象帮我们做了文件封装,#}
{#        也包括了请求头"ConTent-Type,就无需在像原来发字符串的时候加"ConTent-Type了#}
        xhr.send(formdata)
        xhr.onreadystatechange=function () {
            if(xhr.readyState==4){alert(xhr.responseText)}
        }

    }
</script>
</html>
View Code

后端

def fileup(request):
    if request.method=='GET':
        return render(request,'up_file.html')
    else:
        print(request.POST,request.FILES)
        return HttpResponse('OK')
View Code

 使用formdata对象做图片预览

前端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>原生Aja上传文件</title>
</head>
<body>
<h1>原生ajax上传文件</h1>
<div id="container"></div>
<p><input type="file"  id="f1"></p>
<p><input id="f2" type="button" onclick="fileup()" value="上传"></p>
</body>
<script>
    function fileup(){
        var formdata=new FormData()
{#        要想发文件必须借助一个特殊的 formdata对象,帮助我们封装 文件对象 #}
        formdata.append('k1','v2')
        formdata.append('k1',document.getElementById('f1').files[0])
{#        获取文件对象.files得到是一个列表(全部的文件对象)获取第1个切片[0]#}
        var xhr= new XMLHttpRequest()
        xhr.open('POST','/fileup/')
{#        xhr.setRequestHeader("ConTent-Type" ,"application/x-www-form-urlencoded")#}
{#        切记 既然文件对象帮我们做了文件封装,#}
{#        也包括了请求头"ConTent-Type,就无需在像原来发字符串的时候加"ConTent-Type了#}
        xhr.send(formdata)
        xhr.onreadystatechange=function () {
            if(xhr.readyState==4){
                var filepath=xhr.responseText
{#                获取服务端返回的文件路径#}
                var tag=document.createElement('img')
                tag.src="/"+filepath
{#                在本地生成一个img标签显示#}
                document.getElementById('container').appendChild(tag)

                }
        }
View Code

后端

def fileup(request):
    print('ok')
    if request.method=='GET':
        return render(request,'up_file.html')
    else:
        print('OK')
        fileobj=request.FILES.get('k1')
        filepath=os.path.join('static',fileobj.name)
        with open(filepath,'wb') as f:
            for chunk in fileobj.chunks():
                f.write(chunk)
        return HttpResponse(filepath)
View Code

 

2、jQuery Ajax文件上传预览

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>原生Aja上传文件</title>
</head>
<body>
<h1>原生ajax上传文件</h1>
<div id="container"></div>
<p><input type="file" id="f1"></p>
<p><input id="f2" type="button" onclick="Queryup()" value="上传"></p>
<script src="/static/zhanggen.js"></script>
<script>
 function Queryup() {
    var formdata=new FormData()
{#   $(document.getElementById('f1'))       #}
{#    doc对象转换成Jquery对象 $(doc对象)    #}
{#    jQueryup对象转成doc对象 jQuery对象[0] #}
{#    $('#f1')[0]#}
    formdata.append("k1", $('#f1')[0].files[0])
    $.ajax({
        url:'/fileup/',
        type:'POST',
        contentType:false,
{#        告诉Jquery不要对请求头做特殊处理,因为formDta已经把数据封装好了#}
        processData:false,
        data:formdata ,
        success:function (args) {
           var ele=document.createElement('img')
            ele.src="/"+ args
           document.getElementById('container') .appendChild(ele)
        }
    })
}

</script>
</body>
</html>
View Code

 

 3.iframe+form标签伪造ajax操作(兼容性更好)

由于FormData对象是HTML5之后提出的新对象,不兼容之前老版本的浏览器;

一般JS的上传插件都是通过 iframe+form伪造出来的,所以这种上传方法的兼容性会更好些;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>伪造Ajax上传</title>
</head>
<body>
<h1>伪造Ajax上传</h1>
<form method="post" id="f1" action="/fileup/" target='ifr'enctype="multipart/form-data">
  <p><input type="file" name="k1"></p>
  <p><iframe id="ifr"name="ifr" style="display: none"></iframe></p>
  <p><input type="button" value="提交" onclick="upfile()"></p>
</form>
<div id="container"></div>
</body>
<script>
function upfile() {
{#    找到iframe标签在线绑定事件 页面加载事件()#}
    document.getElementById('ifr').onload=loadIframe
{#    使用.submit()方法 提交表单#}
    document.getElementById('f1').submit()
                }
function loadIframe() {
{#    服务端有返回值 iframe标签就会加载,利用此特性绑定 加载事件,然后创建img标签,apendchilder到 一个div中显示 #}
    var return_value=document.getElementById('ifr').contentWindow.document.body.innerHTML
    var tag=document.createElement('img')
    tag.src='/'+return_value
    document.getElementById('container').appendChild(tag)}
</script>
</html>
View Code

 

4.Ajax文件上传方式总结

上传方法总结

上传文件--->iframe+input(伪造ajax)

上传数据---->Jquery、XMLHttpRespose(原生ajax)

图片预览功能实现思路:

1、上传图片到服务端

2、服务端返回一个URL到客户端

3、客户端再去通过img标签src服务端的返回的URL地址 

 

5.ajax长连接(不断刷新)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="/static/jquery-3.2.1.js"></script>
</head>
<body>
<div id="time">{{ c_time }}</div>
</body>
<script>
    $(function () {
        GetTime()
    });

    function GetTime() {
        $.ajax({
            url:{% url 'gettime' %},
            type: 'POST',
            data: {'csrfmiddlewaretoken': "{{ csrf_token }}"},
            dataType: 'JSON',
            success: function (res) {
                $('#time').text(res);
                GetTime()


            }
        })
    }
</script>
</html>
不断更新当前时间

 

 

 

 

 三、jsonp跨域

 一般来说位于www.Laden.com下的网页,是无法和 www.Aobam.com以及任何其他服务器跨域沟通的,由于浏览器同源策略!

什么是同源策略呢?

1.当客户端发送一个GET请求 服务端返回字符串(字符串若包含JS代码,再让浏览器去其他网站获取数据)

2.这时客户端(浏览器)就不能再去发送请求到其他服务端的(除非带有src属性的标签例外

3.如果客户端发送了请求到其他服务端下,其他服务器也会收到,但在其他服务端再返回到浏览器时会被浏览器阻止掉

实验证明

 API(http://127.0.0.1:8000/)

def data(request):
    print('跨域请求来了!!')
    userlist=["alex","egon",'eric']
    return HttpResponse(json.dumps(userlist))
View Code

跨域者(http://127.0.0.1:8086)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>主页</title>
</head>
<body>
<h1>jsop</h1>
<ul id="user">

</ul>
<input type="button" value="获取API的用户列表" onclick="getusers()">
</body>
<script src="/static/zhanggen.js"></script>
<script>
function getusers(){
    var xhs=new XMLHttpRequest()
    xhs.open('GET','http://www.api.com:8000/data/')
    xhs.send()
    xhs.onreadystatechange=function () {
        if(xhs.readyState==4){
            var content=xhs.responseText
            console.log(content)
        }
    }
}

</script>
</html>
View Code

 

 

 

 

 思考:

浏览器的同源策略不会限制带有src属性的标签跨域向其他服务器发送请求

有些程序员机制的利用了这一点,绕开了浏览器的同源策略,发明了jsonp既保证了浏览的安全策略,也解决了浏览器跨站访问数据的问题;

 

Jsonp原理

啰嗦版

1.定义个名为的函数 列入名为b;

2.使用JS动态创建script标签(例如:tag.src='http://www.api.com:8000/data/?functionname=b)通过带有src属性的script标签,跨域向其他服务器发送GET请求;

所以JSONP只能发送GET请求

3.其他服务器收到后 获取函数名 v=request.GET.get('functionname')

两人交互约定很重要啊

4.由于客户端浏览器收到了函数名+括号会立即执行 最初定义的函数B

简洁版

1、客户端定义函数
2、客户端把函数名发给其他服务端
3.其他服务端 拼接一个 函数(参数)返回给客户端
4.客户端执行

一言以敝之版

客户端定义函数,服务端字符串拼接 函数、()、参数,返回客户端,客户端执行最初定义的函数(参数)

 

 代码版

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>主页</title>
</head>
<body>
<h1>jsop</h1>
<ul id="user">

</ul>
<input type="button" value="获取API的用户列表" onclick="getusers()">
</body>
<script src="/static/zhanggen.js"></script>
<script >
    function getusers() {
      var tag=document.createElement('script')
        tag.src='http://www.api.com:8000/data/?functionname=b'
      document.head.appendChild(tag)
        
    }
function b(args) {
   document.getElementById('user').innerHTML=args
}

</html>
View Code

其他服务器

def data(request):
    v=request.GET.get('functionname')
    print('跨域请求来了!!')
    userlist=["alex","egon",'eric']
    temp='%s(%s)'% (v,userlist)
    return HttpResponse(temp)
View Code

 

 既然傻傻的你,早已看透了JSONP跨域访问的一切,JjQuery也会,于是它可以发送JSONP请求封装在了自己的ajax里面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>主页</title>
</head>
<body>
<h1>jsop</h1>
<ul id="user">

</ul>
<input type="button" value="获取API的用户列表" onclick="getusers()">
</body>
<script src="/static/zhanggen.js"></script>
<script >
        $.ajax({
            url:'http://www.api.com:8000/data/',
            type:'get',
            dataType:'jsonp',
            jsonp:'functionname',
            jsonpCallback:'b'
        })
    }
function b(args) {
   document.getElementById('user').innerHTML=args
}
</script>

</html>
View Code

 

 

 三、CORS跨站资源共享

 看完了jsonp的跨域方式,是不是赶紧有些复杂呢?而且还只能发跨域的GET请求! 我就TM想跨域访问,还是我情他愿的事情,咋就浏览器就非得给我阻挡一下子。

其实不是的只要第三方网站,返回客户端时响应头里有特殊标记(令牌), 浏览器看到就不会阻止了这就是CORS跨站共享;

简单请求(1次请求1次响应)

请求方式:HEAD、GET、POST

def newdata(request):
    userlist = ["alex", "egon", 'eric']
    userlist=json.dumps(userlist)
    obj=HttpResponse(userlist)
    obj['Access-Control-Allow-Origin']='http://www.zhanggen.com:8086'
    # 允许http://www.zhanggen.com:8086访问本域下的数据
    return obj
View Code

允许所有客户端跨站访问本域名下的数据

def newdata(request):
    userlist = ["alex", "egon", 'eric']
    userlist=json.dumps(userlist)
    obj=HttpResponse(userlist)
    # obj['Access-Control-Allow-Origin']='http://www.zhanggen.com:8086'
    # 允许http://www.zhanggen.com:8086访问本域下的数据
    obj['Access-Control-Allow-Origin']='*'
    # 允许所有人访问本域下的数据
    return obj
View Code

 

复杂的请求(2次请求2次响应)

请求方式 options

其实有些请求方式会发2次请求带服务端(多一个预检环节)

例如delete请求会以option的方式发送1个预检的请求(不同于get/post请求,不发请求头,请求体)

如果服务端响应客户端允许操作之后

客户端校验 再发delete请求

def newdata(request):
    if request.method=='OPTIONS':
        print('预检')
        obj=HttpResponse()
        #允许所有客户端跨站访问本域数据
        obj['Access-Control-Allow-Origin'] ="*"
        #允许客户端使用delete方法
        obj["Access-Control-Allow-Methods"]="DELETE"
        return obj
    else:
        obj=HttpResponse('OK')
        #客户端使用delete方法发送第2次请求时,也要设置响应头允许
        obj['Access-Control-Allow-Origin'] = "*"
        return obj
View Code

 

 

 

 

 

 

博客链接:

银角大王:http://www.cnblogs.com/wupeiqi/articles/5703697.html

二龙湖浩哥:http://www.cnblogs.com/yuanchenqi/articles/7429279.html#3769378

posted on 2017-07-08 15:47  Martin8866  阅读(738)  评论(0编辑  收藏  举报