Maison > Article > interface Web > Explication détaillée de la stratégie ajax et de même origine mise en œuvre par JS
JS et Ajax sont tous deux essentiels dans nos programmes, et ils sont également étroitement liés. Dans cet article, nous partageons principalement avec vous des exemples de politiques ajax et de même origine implémentées dans JS. Elles ont une bonne valeur de référence et nous espérons que cela pourra aider tout le monde.
1. Examen d'ajax implémenté par jQuery
Parlons d'abord des avantages et des inconvénients d'ajax
Avantages :
AJAX utilise la technologie Javascript pour envoyer des requêtes asynchrones au serveur
AJAX n'en a pas besoin ; pour actualiser la page entière ;
Étant donné que le contenu de la réponse du serveur n'est plus la page entière, mais une partie de la page, AJAX a des performances élevées
ajax implémenté par jqueryindex.html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="{% static 'JS/jquery-3.1.1.js' %}"></script> </head> <body> <button class="send_Ajax">send_Ajax</button> <script> //$.ajax的两种使用方式: //$.ajax(settings); //$.ajax(url,[settings]); $(".send_Ajax").click(function(){ $.ajax({ url:"/handle_Ajax/", type:"POST", data:{username:"Yuan",password:123}, success:function(data){ alert(data) }, //=================== error============ error: function (jqXHR, textStatus, err) { // jqXHR: jQuery增强的xhr // textStatus: 请求完成状态 // err: 底层通过throw抛出的异常对象,值与错误类型有关 console.log(arguments); }, //=================== complete============ complete: function (jqXHR, textStatus) { // jqXHR: jQuery增强的xhr // textStatus: 请求完成状态 success | error console.log('statusCode: %d, statusText: %s', jqXHR.status, jqXHR.statusText); console.log('textStatus: %s', textStatus); }, //=================== statusCode============ statusCode: { '403': function (jqXHR, textStatus, err) { console.log(arguments); //注意:后端模拟errror方式:HttpResponse.status_code=500 }, '400': function () { } } }) }) </script> </body> </html>Views.py
import json,time def index(request): return render(request,"index.html") def handle_Ajax(request): username=request.POST.get("username") password=request.POST.get("password") print(username,password) time.sleep(10) return HttpResponse(json.dumps("Error Data!"))Paramètres $.ajaxParamètres de requête
######################------------data---------################ data: 当前ajax请求要携带的数据,是一个json的object对象,ajax方法就会默认地把它编码成某种格式 (urlencoded:?a=1&b=2)发送给服务端;此外,ajax默认以get方式发送请求。 function testData() { $.ajax("/test",{ //此时的data是一个json形式的对象 data:{ a:1, b:2 } }); //?a=1&b=2 ######################------------processData---------################ processData:声明当前的data数据是否进行转码或预处理,默认为true,即预处理;if为false, 那么对data:{a:1,b:2}会调用json对象的toString()方法,即{a:1,b:2}.toString() ,最后得到一个[object,Object]形式的结果。 ######################------------contentType---------################ 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对象 views.py: json.loads(request.body.decode("utf8")) ######################------------traditional---------################ traditional:一般是我们的data数据有数组时会用到 :data:{a:22,b:33,c:["x","y"]}, traditional为false会对数据进行深层次迭代;Paramètres de réponse
/* dataType: 预期服务器返回的数据类型,服务器端返回的数据会根据这个值解析后,传递给回调函数。 默认不需要显性指定这个属性,ajax会根据服务器返回的content Type来进行转换; 比如我们的服务器响应的content Type为json格式,这时ajax方法就会对响应的内容 进行一个json格式的转换,if转换成功,我们在success的回调函数里就会得到一个json格式 的对象;转换失败就会触发error这个回调函数。如果我们明确地指定目标类型,就可以使用 data Type。 dataType的可用值:html|xml|json|text|script 见下dataType实例 */
Petit exercice : Calculer la somme de deux nombres
Méthode 1 : Le contentType est non spécifié ici : la valeur par défaut est urlencode.
index.html<!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"> <title>Title</title> <script src="/static/jquery-3.2.1.min.js"></script> <script src="http://apps.bdimg.com/libs/jquery.cookie/1.4.1/jquery.cookie.js"></script> </head> <body> <h1>计算两个数的和,测试ajax</h1> <input type="text" class="num1">+<input type="text" class="num2">=<input type="text" class="ret"> <button class="send_ajax">sendajax</button> <script> $(".send_ajax").click(function () { $.ajax({ url:"/sendAjax/", type:"post", headers:{"X-CSRFToken":$.cookie('csrftoken')}, data:{ num1:$(".num1").val(), num2:$(".num2").val(), }, success:function (data) { alert(data); $(".ret").val(data) } }) }) </script> </body> </html>views.py
def index(request): return render(request,"index.html") def sendAjax(request): print(request.POST) print(request.GET) print(request.body) num1 = request.POST.get("num1") num2 = request.POST.get("num2") ret = float(num1)+float(num2) return HttpResponse(ret)
Méthode 2 : Spécifiez conentType comme données json à envoyer :
index2.html<script> $(".send_ajax").click(function () { $.ajax({ url:"/sendAjax/", type:"post", headers:{"X-CSRFToken":$.cookie('csrftoken')}, //如果是json发送的时候要用headers方式解决forbidden的问题 data:JSON.stringify({ num1:$(".num1").val(), num2:$(".num2").val() }), contentType:"application/json", //客户端告诉浏览器是以json的格式发的数据,所以的吧发送的数据转成json字符串的形式发送 success:function (data) { alert(data); $(".ret").val(data) } }) }) </script>views.py
def sendAjax(request): import json print(request.POST) #<QueryDict: {}> print(request.GET) #<QueryDict: {}> print(request.body) #b'{"num1":"2","num2":"2"}' 注意这时的数据不再POST和GET里,而在body中 print(type(request.body.decode("utf8"))) # <class 'str'> # 所以取值的时候得去body中取值,首先得反序列化一下 data = request.body.decode("utf8") data = json.loads(data) num1= data.get("num1") num2 =data.get("num2") ret = float(num1)+float(num2) return HttpResponse(ret)
2. Ajax implémenté par JS
1. En fait, AJAX ajoute un objet supplémentaire à l'objet Javascript :XMLHttpRequest. Toutes les interactions asynchrones sont effectuées à l'aide de l'objet XMLHttpServlet. En d’autres termes, il suffit d’apprendre un nouvel objet Javascript.
var xmlHttp = new XMLHttpRequest(); (La plupart des navigateurs prennent en charge la spécification DOM2) Notez que la prise en charge de XMLHttpRequest par chaque navigateur est également différente ! Afin de résoudre les problèmes de compatibilité du navigateur, la méthode suivante est proposée pour créer un objet XMLHttpRequest :function createXMLHttpRequest() { var xmlHttp; // 适用于大多数浏览器,以及IE7和IE更高版本 try{ xmlHttp = new XMLHttpRequest(); } catch (e) { // 适用于IE6 try { xmlHttp = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { // 适用于IE5.5,以及IE更早版本 try{ xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e){} } } return xmlHttp; }2. >
1. Ouvrir la connexion avec le serveur (open) Après avoir obtenu l'objet XMLHttpRequest, vous pouvez appeler la méthode open() de l'objet pour ouvrir la connexion avec le serveur. Les paramètres de la méthode open() sont les suivants :
open(method, url, async) :method : méthode de requête, généralement GET ou POST ; : Adresse du serveur demandée, par exemple : /ajaxdemo1/AServlet. S'il s'agit d'une requête GET, vous pouvez également ajouter des paramètres après l'URL ;
async : Ce paramètre n'a pas besoin d'être donné. true, indiquant une requête asynchrone ; var xmlHttp = createXMLHttpRequest();xmlHttp.open("GET", "/ajax_get/?a=1", true);
2. Envoyer la demande
Après avoir utilisé open pour ouvrir la connexion, vous pouvez appeler la méthode send() de l'objet XMLHttpRequest pour envoyer la demande. Les paramètres de la méthode send() sont des paramètres de requête POST, c'est-à-dire le contenu du corps de la requête correspondant au protocole HTTP. S'il s'agit d'une requête GET, les paramètres doivent être connectés après l'URL. Remarque : s'il n'y a pas de paramètres, null doit être donné comme paramètre ! Si null n'est pas donné en paramètre, le navigateur FireFox risque de ne pas pouvoir envoyer de requêtes normalement ! xmlHttp.send(null);3. Recevoir la réponse du serveur (5 états, 4 processus)
Lorsque la demande est envoyée après Cela signifie que le côté serveur démarre l'exécution, mais la réponse du côté serveur n'a pas encore été reçue. Ensuite, nous recevons la réponse du serveur. L'objet XMLHttpRequest a un événement onreadystatechange, qui est appelé lorsque l'état de l'objet XMLHttpRequest change. Ce qui suit présente les cinq états de l'objet XMLHttpRequest : 0 : l'initialisation n'est pas terminée, l'objet XMLHttpRequest a seulement été créé et la méthode open() n'a pas été appelée1 : la requête ; a démarré, la méthode open() n'a pas été appelée A été appelée, mais la méthode send() n'a pas été appelée ; 2 : Demande d'état d'achèvement de l'envoi, la méthode send() a été appelée 3 : Commencez à lire la réponse du serveur ;
4 : Fin de la lecture de la réponse du serveur . l'événement onreadystatechange sera déclenché lorsque l'état est 1, 2, 3, 4. Le code suivant sera exécuté quatre fois ! Correspondant aux quatre états de XMLHttpRequest!
Mais généralement, nous ne nous soucions que du dernier état, c'est-à-dire que le client n'apportera aucune modification avant la fin de la lecture de la réponse du serveur. Nous pouvons obtenir le statut de l'objet XMLHttpRequest via l'attribut readyState de l'objet XMLHttpRequest.
xmlHttp.onreadystatechange = function() { alert('hello'); };Remarque :
xmlHttp.onreadystatechange = function() { if(xmlHttp.readyState == 4) { alert('hello'); } };
S'il s'agit d'une demande de publication :
xmlHttp.onreadystatechange = function() { if(xmlHttp.readyState == 4 && xmlHttp.status == 200) { alert(xmlHttp.responseText); } };
S'il s'agit d'un get request : Petit exercice : Identique à l'exercice ci-dessus, juste d'une manière différente (vous pouvez le comparer avec jQuery)
views.py
基于JS的ajax没有Content-Type这个参数了,也就不会默认是urlencode这种形式了,需要我们自己去设置 <1>需要设置请求头:xmlHttp.setRequestHeader(“Content-Type”, “application/x-www-form-urlencoded”); 注意 :form表单会默认这个键值对不设定,Web服务器会忽略请求体的内容。 <2>在发送时可以指定请求体了:xmlHttp.send(“username=yuan&password=123”) 基于jQuery的ajax和form发送的请求,都会默认有Content-Type,默认urlencode, Content-Type:客户端告诉服务端我这次发送的数据是什么形式的 dataType:客户端期望服务端给我返回我设定的格式
xmlhttp.open("get","/sendAjax/?a=1&b=2");
JS实现ajax小结
创建XMLHttpRequest对象; 调用open()方法打开与服务器的连接; 调用send()方法发送请求; 为XMLHttpRequest对象指定onreadystatechange事件函数,这个函数会在 XMLHttpRequest的1、2、3、4,四种状态时被调用; XMLHttpRequest对象的5种状态,通常我们只关心4状态。 XMLHttpRequest对象的status属性表示服务器状态码,它只有在readyState为4时才能获取到。 XMLHttpRequest对象的responseText属性表示服务器响应内容,它只有在 readyState为4时才能获取到!
总结:
- 如果"Content-Type"="application/json",发送的数据是对象形式的{},需要在body里面取数据,然后反序列化 = 如果"Content-Type"="application/x-www-form-urlencoded",发送的是/index/?name=haiyan&agee=20这样的数据, 如果是POST请求需要在POST里取数据,如果是GET,在GET里面取数据
实例(用户名是否已被注册)
7.1 功能介绍
在注册表单中,当用户填写了用户名后,把光标移开后,会自动向服务器发送异步请求。服务器返回true或false,返回true表示这个用户名已经被注册过,返回false表示没有注册过。
客户端得到服务器返回的结果后,确定是否在用户名文本框后显示“用户名已被注册”的错误信息!
7.2 案例分析
页面中给出注册表单;
在username表单字段中添加onblur事件,调用send()方法;
send()方法获取username表单字段的内容,向服务器发送异步请求,参数为username;
django 的视图函数:获取username参数,判断是否为“yuan”,如果是响应true,否则响应false
参考代码:
<script type="text/javascript"> function createXMLHttpRequest() { try { return new XMLHttpRequest(); } catch (e) { try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { return new ActiveXObject("Microsoft.XMLHTTP"); } } } function send() { var xmlHttp = createXMLHttpRequest(); xmlHttp.onreadystatechange = function() { if(xmlHttp.readyState == 4 && xmlHttp.status == 200) { if(xmlHttp.responseText == "true") { document.getElementById("error").innerText = "用户名已被注册!"; document.getElementById("error").textContent = "用户名已被注册!"; } else { document.getElementById("error").innerText = ""; document.getElementById("error").textContent = ""; } } }; xmlHttp.open("POST", "/ajax_check/", true, "json"); xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); var username = document.getElementById("username").value; xmlHttp.send("username=" + username); } </script> //--------------------------------------------------index.html <h1>注册</h1> <form action="" method="post"> 用户名:<input id="username" type="text" name="username" onblur="send()"/><span id="error"></span><br/> 密 码:<input type="text" name="password"/><br/> <input type="submit" value="注册"/> </form> //--------------------------------------------------views.py from django.views.decorators.csrf import csrf_exempt def login(request): print('hello ajax') return render(request,'index.html') # return HttpResponse('helloyuanhao') @csrf_exempt def ajax_check(request): print('ok') username=request.POST.get('username',None) if username=='yuan': return HttpResponse('true') return HttpResponse('false')
三、同源策略与jsonp
同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
同源策略,它是由Netscape提出的一个著名的安全策略。现在所有支持JavaScript 的浏览器都会使用这个策略。所谓同源是指,域名,协议,端口相同。当一个浏览器的两个tab页中分别打开来 百度和谷歌的页面当浏览器的百度tab页执行一个脚本的时候会检查这个脚本是属于哪个页面的,即检查是否同源,只有和百度同源的脚本才会被执行。如果非同源,那么在请求数据时,浏览器会在控制台中报一个异常,提示拒绝访问。
jsonp(jsonpadding)
之前发ajax的时候都是在自己给自己的当前的项目下发
现在我们来实现跨域发。给别人的项目发数据,
创建两个项目,先来测试一下
项目一:
<body> <h1>项目一</h1> <button class="send_jsonp">jsonp</button> <script> $(".send_jsonp").click(function () { $.ajax({ url:"http://127.0.0.1:8080/ajax_send2/", #去请求项目二中的url success:function (data) { console.log(data) } }) }) </script> </body>
项目二:
=========================index.html=============== <h1>项目二</h1> <button class="send_jsonp">jsonp</button> <script> $(".send_jsonp").click(function () { $.ajax({ url:"/ajax_send2/", success:function (data) { console.log(data) } }) }) </script> </body> =========================views=============== from django.shortcuts import render,HttpResponse # Create your views here. def index(request): return render(request, "index.html") def ajax_send2(request): print(222222) return HttpResponse("hello")
出现了一个错误,这是因为同源策略给限制了,这是游览器给我们报的一个错
(但是注意,项目2中的访问已经发生了,说明是浏览器对非同源请求返回的结果做了拦截。)
注意:a标签,form,img标签,引用cdn的css等也属于跨域(跨不同的域拿过来文件来使用),不是所有的请求都给做跨域,(为什么要进行跨域呢?因为我想用人家的数据,所以得去别人的url中去拿,借助script标签)
如果用script请求的时候也会报错,当你你返回的数据是一个return Httpresponse(“项目二”)只是一个名字而已,js中如果有一个变量没有声明,就会报错。就像下面的这样了
<script src="http://127.0.0.1:8080/ajax_send2/"> 项目二 </script>
只有发ajax的时候给拦截了,所以要解决的问题只是针对ajax请求能够实现跨域请求
解决同源策源的两个方法:
1、jsonp(将JSON数据填充进回调函数,这就是JSONP的JSON+Padding的含义。)
jsonp是json用来跨域的一个东西。原理是通过script标签的跨域特性来绕过同源策略。
思考:这算怎么回事?
<script src="http://code.jquery.com/jquery-latest.js"></script>
借助script标签,实现跨域请求,示例:
所以只是单纯的返回一个也没有什么意义,我们需要的是数据
如下:可以返回一个字典,不过也可以返回其他的(简单的解决了跨域,利用script)
项目一:
<body> <h1>项目一</h1> <button class="send_jsonp">jsonp</button> <script> $(".send_jsonp").click(function () { $.ajax({ url:"", success:function (data) { console.log(data) } }) }); function func(arg) { console.log(arg) } </script> <script src="http://127.0.0.1:8080/ajax_send2/"></script> </body>
项目二:
def ajax_send2(request): import json print(222222) # return HttpResponse("func('name')") s = {"name":"haiyan","age":12} # return HttpResponse("func('name')") return HttpResponse("func('%s')"%json.dumps(s)) #返回一个func()字符串,正好自己的ajax里面有个func函数,就去执行func函数了, arg就是传的形参
这样就会取到值了
这其实就是JSONP的简单实现模式,或者说是JSONP的原型:创建一个回调函数,然后在远程服务上调用这个函数并且将JSON 数据形式作为参数传递,完成回调。
将JSON数据填充进回调函数,这就是JSONP的JSON+Padding的含义。
但是以上的方式也有不足,回调函数的名字和返回的那个名字的一致。并且一般情况下,我们希望这个script标签能够动态的调用,而不是像上面因为固定在html里面所以没等页面显示就执行了,很不灵活。我们可以通过javascript动态的创建script标签,这样我们就可以灵活调用远程服务了。
解决办法:javascript动态的创建script标签
===========================jQuery实现===================== {# 创建一个script标签,让他请求一次,请求完了删除他#} //动态生成一个script标签,直接可以定义个函数,放在函数里面 function add_script(url) { var ele_script = $("<script>"); ele_script.attr("src",url); ele_script.attr("id","script"); $("body").append(ele_script); $("#script").remove() } $(".kuayu").click(function () { add_script("http://127.0.0.1:8080/ajax_send2/") }); </script> ==================js实现========================== <button onclick="f()">sendAjax</button> <script> function addScriptTag(src){ var script = document.createElement('script'); script.setAttribute("type","text/javascript"); script.src = src; document.body.appendChild(script); document.body.removeChild(script); } function func(name){ alert("hello"+name) } function f(){ addScriptTag("http://127.0.0.1:7766/SendAjax/") } </script>
为了更加灵活,现在将你自己在客户端定义的回调函数的函数名传送给服务端,服务端则会返回以你定义的回调函数名的方法,将获取的json数据传入这个方法完成回调:
function f(){ addScriptTag("http://127.0.0.1:7766/SendAjax/?callbacks=func") }
将视图views改为
def SendAjax(request): import json dic={"k1":"v1"} print("callbacks:",request.GET.get("callbacks")) callbacks=request.GET.get("callbacks") #注意要在服务端得到回调函数名的名字 return HttpResponse("%s('%s')"%(callbacks,json.dumps(dic)))
四、jQuery对JSONP的实现
getJSON
jQuery框架也当然支持JSONP,可以使用$.getJSON(url,[data],[callback])方法
<button onclick="f()">sendAjax</button> <script> function f(){ $.getJSON("http://127.0.0.1:7766/SendAjax/?callbacks=?",function(arg){ alert("hello"+arg) }); 匿名函数 } </script>
8002的views不改动。
结果是一样的,要注意的是在url的后面必须添加一个callback参数,这样getJSON方法才会知道是用JSONP方式去访问服务,callback后面的那个?是内部自动生成的一个回调函数名。
此外,如果说我们想指定自己的回调函数名,或者说服务上规定了固定回调函数名该怎么办呢?我们可以使用$.ajax方法来实现
$.ajax
<script> function f(){ $.ajax({ url:"http://127.0.0.1:7766/SendAjax/", dataType:"jsonp", jsonp: 'callbacks', #键 jsonpCallback:"SayHi" #函数的名字 }); } function SayHi(arg){ alert(arg); } </script>
8002的views不改动。
当然,最简单的形式还是通过回调函数来处理:
<script> function f(){ $.ajax({ url:"http://127.0.0.1:7766/SendAjax/", dataType:"jsonp", //必须有,告诉server,这次访问要的是一个jsonp的结果。 jsonp: 'callbacks', //jQuery帮助随机生成的:callbacks="wner" success:function(data){ alert("hi "+data) } }); } </script>
jsonp: 'callbacks'就是定义一个存放回调函数的键,jsonpCallback是前端定义好的回调函数方法名'SayHi',server端接受callback键对应值后就可以在其中填充数据打包返回了;
jsonpCallback参数可以不定义,jquery会自动定义一个随机名发过去,那前端就得用回调函数来处理对应数据了。利用jQuery可以很方便的实现JSONP来进行跨域访问。
注意 JSONP一定是GET请求
五、应用
// 跨域请求实例 $(".jiangxiTV").click(function () { $.ajax({ url:"http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403", dataType: 'jsonp', jsonp: 'callback', jsonpCallback: 'list', success:function (data) { console.log(data.data); // [{},{},{},{},{},{}] week_list=data.data; $.each(week_list,function (i,j) { console.log(i,j); // 1 {week: "周一", list: Array(19)} s="<p>"+j.week+"列表</p>"; $(".show_list").append(s); $.each(j.list,function (k,v) { // {time: "0030", name: "通宵剧场六集连播", link: "http://www.jxntv.cn/live/jxtv2.shtml"} a="<p><a href='"+v.link+"'>"+v.name+"</a></p>"; $(".show_list").append(a); }) }) } }) })
相关推荐:
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!