1、什么是json?
JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式。
2. 那么JSON和JavaScript又有什么关系呢?
json对象其实最初就是从JS中衍生出来的一种数据格式,它和JS有着本质的区别。可以说JSON是JavaScript对象的子集,json继承了JavaScript的number,string(" "),bool,null,array,{"name":"egon" ,"age ":18} 注意json只支持双引号 。所以相比其他语言,JavaScript把json字符串解析成JS对象有天然优势。
3. JSON和Python的关系?
Python有Python的数据类型,JS有JS的数据类型,但前后端之所以可以交互,是因为中间有 json字符串做中间转换
4. JSON和JS对象,以及Python的相互转化关系
JSON.stringify(JS对象) 将JS对象序列化成 JSON字符串 ------->python的json.dumps()
JSON.parse('JSON对象') 将json字符串反序列化成 JS对象--------->python的json.loads()
5 什么是Ajax?
AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步Javascript和XML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML,可以指定json),
异步的JavaScript,使用 【JavaScript语言】 以及 相关【浏览器提供类库】 的功能向服务端发送请求,当服务端处理完请求之后,【自动执行某个JavaScript的回调函数】
6 Ajax的应用场景
相对于Form表单而言的,其最大的优势就是页面不刷新,提交时可以偷偷向后台发数据
注册时,输入用户名自动检测用户是否已经存在(监测光标,输入完成后会移动到其他地方,此时发送ajax请求)
登陆时,提示用户名密码错误
删除数据行时,将行ID发送到后台,后台在数据库中删除,数据库删除成功后,在页面DOM中将数据行也删除
7 原生Ajax和Jquery封装的Ajax
使用Ajax直接使用JS的XMLHttp Request对象, 无需引入Jquery了。这样响应客户端携带信息量减少,可节省流量,适用于手机移动端。
8 原生的Ajax(Xmlhttprequest)
XmlHttpRequest对象的主要方法:
a. void open(String method,String url,Boolen async)
用于创建请求
参数:
method: 请求方式(字符串类型),如:POST、GET、DELETE...
url: 要请求的地址(字符串类型)
async: 是否异步(布尔类型)
b. void send(String body)
用于发送请求
参数:
body: 要发送的数据(字符串类型)
c. void setRequestHeader(String header,String value)
用于设置请求头
参数:
header: 请求头的key(字符串类型)
vlaue: 请求头的value(字符串类型)
d. String getAllResponseHeaders()
获取所有响应头
返回值:
响应头数据(字符串类型)
e. String getResponseHeader(String header)
获取响应头中指定header的值
参数:
header: 响应头的key(字符串类型)
返回值:
响应头中指定的header对应的值
f. void abort()
终止请求
XmlHttpRequest对象的属性:
a. Number readyState 状态值(整数) 详细: 0-未初始化,尚未调用open()方法; 1-启动,调用了open()方法,未调用send()方法; 2-发送,已经调用了send()方法,未接收到响应; 3-接收,已经接收到部分响应数据; 4-完成,已经接收到全部响应数据; b. Function onreadystatechange 当readyState的值改变时自动触发执行其对应的函数(回调函数) c. String responseText 服务器返回的数据(字符串类型) d. XmlDocument responseXML 服务器返回的数据(Xml对象) e. Number states 状态码(整数),如:200、404... f. String statesText 状态文本(字符串),如:OK、NotFound...
原生Ajax的四步操作:
创建核心对象XMLhttprequest
与服务器进行连接open
发送请求send
监听readystate
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <h1>XMLHttpRequest - Ajax请求</h1> <input type="button" onclick="XmlGetRequest();" value="Get发送请求" /> <input type="button" onclick="XmlPostRequest();" value="Post发送请求" /> <script src="/jquery-3.3.1.js" type="text/javascript"></script> <script type="text/javascript"> {#这个函数是为了解决不同浏览器的兼容性问题#} function GetXHR(){ var xhr = null; if(XMLHttpRequest){ xhr = new XMLHttpRequest(); }else{ xhr = new ActiveXObject("Microsoft.XMLHTTP"); } return xhr; } function XmlPostRequest(){ var xhr = GetXHR(); // 定义回调函数 xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ // 已经接收到全部响应数据,执行以下操作 var data = xhr.responseText; console.log(data); } }; // 指定连接方式和地址----文件方式 xhr.open('POST', "/test", true); // 设置请求头问题出现了为什么后端request.post方法没有数据呢? {#使用jQuery发送post请求jQuery会默认把 发送的数据(js对象)编码成urlencoded格式,使用原生ajax就不会了#} {#所以使用原生ajax发POST请求之前,请求头中 务必要指定数据的编码格式“Content-Type”, “application/x-www-form-urlencoded”才能发到server端;#} xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-UTF-8'); // 发送请求 xhr.send('n1=1;n2=2;'); } function XmlGetRequest(){ var xhr = GetXHR(); // 定义回调函数 xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ // 已经接收到全部响应数据,执行以下操作 var data = xhr.responseText; console.log(data); } if(xhr.readyState==1){console.log("对象未调用open方法")} if(xhr.readyState==2){console.log("请求发送")} if(xhr.readyState==3){console.log("接收中")} }; // 指定连接方式和地址----文件方式 xhr.open('get', "/test?n1=1", true); // get发送请求,想要传递参数不能在send中传递,只能在open的url里面加?加参数 xhr.send(); } </script> </body> </html>
后端返回数据用httpresponse即可,因为ajax传递字符,相对应的后端也需要同种方式传递
def ajax(request): return render(request, 'ajax.html') def test(request): print('shoudao') n1 = request.GET.get('n1') a = request.GET print(a, n1) return HttpResponse('shoudao')
9 jqeury的Ajax
jquery就是把上述四步封装成整体:
<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>
请求参数的介绍
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会对数据进行深层次迭代;数据就会变成c=x&&c=y可能不会拿到我们想要结果
响应参数
/*
dataType: 预期服务器返回的数据类型,服务器端返回的数据会根据这个值解析后,传递给回调函数。
默认不需要显性指定这个属性,ajax会根据服务器返回的content Type来进行转换;
比如我们的服务器响应的content Type为json格式,这时ajax方法就会对响应的内容
进行一个json格式的转换,if转换成功,我们在success的回调函数里就会得到一个json格式
的对象;转换失败就会触发error这个回调函数。如果我们明确地指定目标类型,就可以使用
data Type。
dataType的可用值:html|xml|json|text|script
见下dataType实例
*/
10 伪造ajax(iframe+form)
iframe其实就是在原页面中开辟了一个新的窗口,可以加载出其他页面,如果我们利用form表单将数据提交到iframe指定的url,系统依然会去执行url对应的view,我们只需要把所需要的数据从iframe的窗口中提取出来即可,把iframe设置为隐藏模式,这样就不会有人发现iframe的存在了,完美的模拟了ajax的不刷新功能。至于回调功能,我们只需要 设置一个iframe的onload即可,别忘了iframe本质上也只是一个窗口。
可以看到iframe就是一个窗口,接下来我们就来伪造ajax了
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>伪造Ajax</title> </head> <body> <input type="text"> <form id="f1" action="/login.html" 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>
11 ajax的一些应用,实现上传和预览功能
ajax要想发送文件,就必须借助JS中formdata对象,( var formdata=new FormData()),formdata对象帮我们把文件 构造成特定的请求体和请求头,在post中也无需设置content-type了,设置了反而会多此一举而出错。
11.1 原生ajax
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>伪造Ajax</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> <div id="preview"></div> <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', '/ajax.html') {# 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 console.log(filepath) {# 获取服务端返回的文件路径#} var tag = document.createElement('img') tag.src = "/" + filepath {# 在本地生成一个img标签显示#} document.getElementById('preview').appendChild(tag) } } } </script> </body> </html>
后端
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)
11.2jquery 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>
11.3 iframe+form
由于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>