Maison  >  Article  >  interface Web  >  Principes AJAX et méthodes inter-domaines CORS

Principes AJAX et méthodes inter-domaines CORS

一个新手
一个新手original
2017-10-25 14:24:384850parcourir

Ajax est l'une des fonctionnalités de base nécessaires au développement front-end. Vous pouvez l'utiliser, mais vous ne comprenez pas nécessairement ses principes et ses connaissances plus approfondies liées à la communication avec le serveur. Au cours des deux derniers jours de tri, j'ai lu beaucoup d'articles et j'ai découvert que mes capacités back-end limitaient mon exploration des domaines de connaissances liés à la communication réseau, et je devrais combler mes lacunes dès que possible.

Parlons de ajax choses liées, y compris une partie de xhr/xdr/ajax/cors/http, qui éliminera certains bagages historiques obsolètes, tels que IE6/7, etc.

L'émergence d'Ajax

En 2005, Jesse James Garrett a proposé la technologie Ajax, appelée Asynchronous Javascript and XML Le cœur d'Ajax est l'objet XMLHttpRequest, appelé en abrégé, cela permet au navigateur de demander des données supplémentaires au serveur sans décharger la page, améliorant considérablement l'expérience utilisateur. Avant cela, cette technologie existait réellement et était mise en œuvre par certaines personnes, mais elle n'était pas populaire et n'était pas prise en charge par les navigateurs. Cependant, après cela, IE5 a introduit l'objet XHR pour la première fois et a pris en charge la technologie XHR, qui a ensuite été prise en charge par tous les navigateurs. ajax

Objets et requêtes XMLHttpRequest

est une API qui fournit au client la fonction de communication entre le serveur et le client sans rafraîchir la page. Il peut non seulement récupérer des données de type XML, mais également tous les types de données. En plus du protocole HTTP, il prend également en charge les protocoles de fichiers et FTP. Nous pouvons créer un nouvel objet XHR via son constructeur. Cette opération doit être effectuée avant toutes les autres opérations : XHR

var xhr = new XMLHttpRequest();
Nous pouvons facilement voir la chaîne de prototypes de

via la console :XHR. Il a des méthodes et des attributs sur la chaîne de prototypes et sur elle-même. Jetons maintenant un œil à nos méthodes couramment utilisées : Object -> EventTarget -> XMLHttpRequestEventTarget -> XMLHttpRequest
Principes AJAX et méthodes inter-domaines CORS

Expliquons plusieurs de ses principales méthodes. en créant un nouvel objet xhr, vous devez d'abord appeler sa méthode

 : open()

// 第一个参数可以为get/post等,表示该请求的类型
// 第二个参数是请求的url,可以为相对路径或绝对路径
// 第三个参数代表是否异步,为true时异步,为false时同步
// 第四五个参数为可选的授权使用的参数,因为安全性不推荐明文使用
xhr.open('get', 'example.php', true, username, password);
Affecté par la politique de même origine ici, lorsque l'url du deuxième paramètre est cross-domain, elle sera bloquée par le navigateur Signaler une erreur de sécurité. La politique de même origine signifie que le protocole, le nom de domaine et le port de la page actuelle et l'URL cible sont les mêmes. Comme nous le mentionnerons plus tard, les navigateurs autres qu'IE implémentent des requêtes inter-domaines via des objets XHR, il suffit de définir l'URL sur une URL absolue.

Lorsque la requête d'initialisation est terminée, nous appelons la méthode

pour envoyer la requête : send()

var data = new FormData();
data.append('name', 'Nicholas');
// 接受一个请求主体发送的数据,如果不需要,传入null
xhr.send(data);
Lorsque le type de requête est

, les paramètres de send() seront être ignoré et colocalisé Est nul, les paramètres passés par send() affecteront la valeur par défaut de notre en-tête de requête get/head Ce champ représente le type de contenu de ressource renvoyé et est utilisé pour le traitement du navigateur s'il n'est pas défini ou dans. certains scénarios, navigation Le serveur effectuera un reniflage MIME pour déterminer comment gérer la ressource renvoyée. content-type

définit les données

dans XHR2级, qui sont utilisées pour la sérialisation des données de formulaire courantes : FormData

// 直接传入表单id
var data = new FormData(document.getElementById('user-form'));

// 创建类表单数据
var data = new FormData();
data.append('name', 'Nicholas');

// `FormData`可以直接被send()调用,会自动修改xhr的content-type头部
xhr.send(data);

// 请求头部的content-type: multipart/form-data; boundary=----WebKitFormBoundaryjn3q2KKRYrEH55Vz

// 请求的上传数据 Request Payload:
------WebKitFormBoundaryjn3q2KKRYrEH55Vz
Content-Disposition: form-data; name="name"

Nicholas
------WebKitFormBoundaryjn3q2KKRYrEH55Vz--

Les méthodes couramment utilisées incluent FormData, les deux méthodes couramment utilisées sont similaires aux tableaux ne sera pas expliqué à nouveau. append/delete/entries/forEach/get/getAll/has/keys/set/values

méthode de requête

est le type de requête le plus courant. Les paramètres de chaîne de requête peuvent être ajoutés à la fin de l'URL. Pour XHR, la chaîne de requête doit être correctement codée. les paires de valeurs doivent être codées en utilisant GET, et les paires clé-valeur sont séparées par encodeURIComponent() : &

// 封装序列化键值对
function addURLParam(url, name, value) {
    url += (url.indexOf('?') === -1 ? '?' : '&';
    url += encodeURIComponent(name) + '=' + encodeURIComponent(value);
    return url;
}

la fréquence de la demande est juste derrière la demande POST et est généralement envoyée plus fréquemment Data, et le format n'est pas limité, les données sont transmises à GET en tant que paramètre. send()

HTTP propose un total de neuf méthodes de requête. Chaque verbe représente une sémantique différente, mais seules les deux ci-dessus sont couramment utilisées :

 - OPTIONS:返回服务器针对特定资源所支持的HTTP请求方法。也可以利用向Web服务器发送'*'的请求来测试服务器的功能性。 
 - HEAD:向服务器索要与GET请求相一致的响应,只不过响应体将不会被返回。这一方法可以在不必传输整个响应内容的情况下,就可以获取包含在响应消息头中的元信息。 
 - GET:向特定的资源发出请求。 
 - POST:向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的创建和/或已有资源的修改。 
 - PUT:向指定资源位置上传其最新内容。 
 - DELETE:请求服务器删除Request-URI所标识的资源。 
 - TRACE:回显服务器收到的请求,主要用于测试或诊断。 
 - CONNECT:HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
 - PATCH: 用于对资源进行部分修改
Informations d'en-tête HTTP

Chaque. La requête et la réponse HTTP sont accompagnées d'informations d'en-tête, et l'objet xhr nous permet de manipuler certaines informations d'en-tête. Nous pouvons utiliser la méthode

pour définir des informations d'en-tête personnalisées ou modifier les informations d'en-tête normales par défaut du navigateur. En-têtes de requête couramment utilisés : xhr.setRequestHeader()

// 下面的实例是从我本地的一次请求取出的

Accept: 浏览器能够处理的内容类型。// */*
Accept-Charset: 浏览器能够显示的字符集。// 未取到
Accept-Encoding: 浏览器能够处理的压缩编码。// gzip,deflate
Accept-Language: 浏览器当前设置的语言。// zh-CN,zh;q=0.8,en;q=0.6
Connection: 浏览器与服务器之间连接的类型。// keep-alive
Cookie: 当前页面设置的任意Cookie。// JlogDataSource=jomodb
Host: 发出请求的页面所在域。// gzhxy-cdn-oss-06.gzhxy.baidu.com:8090
Referer: 发出请求的页面URI。// http://gzhxy-cdn-oss-06.gzhxy.baidu.com:8090/jomocha/index.php?r=tools/offline/index
User-Agent: 浏览器的用户代理字符串。// Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36
Nous ne modifions généralement pas les informations normales de l'en-tête du navigateur, ce qui peut affecter la réponse du serveur. Si nécessaire, il peut être modifié via

 : xhr.setRequestHeader()

// 传入头部键值对,键值不区分大小写,如果多次设置,则追加
// 此时请求头部的content-type: application/json, text/html
xhr.setRequestHeader('content-type', 'application/json');
xhr.setRequestHeader('content-type', 'application/json');
Le réglage des informations d'en-tête doit être appelé après

et avant open(). Les informations d'en-tête de réponse sont traitées au niveau du backend et ne seront pas expliquées ici. Certaines informations d'en-tête de requête ne peuvent pas être définies, telles que send(), etc. Accept-Encoding, Cookie

Après le retour de la requête, nous pouvons obtenir l'en-tête de réponse :

// 获取指定项的响应头
xhr.getResponseHeader('content-type'); // application/json;charset=utf-8
// 获取所有的响应头部信息
xhr.getAllResponseHeaders();
Voici une brève description de la valeur content-type, qui fait référence au type de contenu HTTP de la requête et réponse, affectant la façon dont le serveur et le navigateur traitent les données, la valeur par défaut est

, celles couramment utilisées sont : text/html

// 包含资源类型,字符编码, 边界字符串三个参数,可选填

text/html;charset=utf-8    // html标签文本
text/plain    // 纯文本
text/css    // css文件
text/javascript    // js文件
// 普通的表单数据,可以通过表单标签的enctype属性指定
application/x-www-form-urlencode
// 发送文件的POST包,包过大需要分片时使用`boundary`属性分割数据作边界
multipart/form-data; boundary=something
// json数据格式
application/json
// xml类型的标记语言
application/xml

XHR对象的响应

我们现在对请求的发起很了解了,接着看下如何拿到响应数据。如果我们给open()传递的第三个参数是true,则代表为同步请求,那么js会被阻塞直到拿到响应,而如果为false则是异步请求,我们只需要绑定xhr.onreadystatechange()事件监听响应即可。最上面的图已经说明了readystate的值含义,所以我们可以:

// xhr v1 的写法,检测readystate的值,为4则说明数据准备完毕,需要在open()前定义
xhr.onreadystatechange = function () {
    if (xhr.readyState === 4) {
        if (xhr.status === 200 || xhr.status === 304) {
            console.log(xhr.responseText);
        } else {
            console.log(xhr.statusText);
        }
    }   
}

// xhr v2 的写法,onload()事件说明数据准备完毕
xhr.onload = function () {
    if (xhr.status === 200 || xhr.status === 304) {
        console.log(xhr.responseText);
    } else {
        console.log(xhr.statusText);
    }
}

xhr对象的响应数据中包含几个属性:

response    // 响应的数据
responseURL    // 发起响应的URL
responseType    // 响应的类型,用于浏览器强行重置响应数据的类型
responseText    // 如果为普通文本,则在这显示
responseXML    // 如果为xml类型文本,在这里显示

数据会出现在responseText/responseXML中的哪一个,取决于服务器返回的MIME类型,当然我们也有一些方式在浏览器端设置如何处理这些数据:

// xhr v1 的写法,设置响应资源的处理类型
xhr.overrideMimeType('text/xml');

// xhr v2 的写法, 可用值为 arraybuffer/blob/document/json/text
xhr.responseType = 'document';

响应数据相关的属性默认为null / '',只有当请求完成并被正确解析的时候才会有值,取决于responseType的值,来确定response/responseText/responseXML谁最终具有值。

XHR的高级功能

xhr v2里提供了超时和进度事件。

超时

xhr.timeout = 1000;    // 1分钟,单位为ms
xhr.ontimeout = function () {};

在请求send()之后开始计时,等待timeout时长后,如果没有收到响应,则触发ontimeout()事件,超时会将readystate=4,直接触发onreadystatechange()事件。

请求进度

像上图所示,xhr v2定义了不同的进度事件:loadstart/progress/error/abort/load/loadend,这其中我们已经说过了onload()事件为内容加载完成可用。现在说一下onprogress()进度事件:

xhr.onprogress = function (event) {
    if (event.lengthComputable) {
        console.log(event.loaded / event.total);
    }
}

该事件会接收一个event对象,其target属性为该xhr对象,lengthComputable属性为total size是否已知,即是否可用进度信息,loaded属性为已经接收的字节数,total为总字节数。该事件会在数据接收期间不断触发,但间隔不确定。

跨域CORS

提到XHR对象,我们就会讲到跨域问题,它是为了预防某些恶意行为的安全策略,但有时候我们需要跨域来实现某些功能。需要注意的是跨域并不仅仅是前端单方面的事情,它需要后端代码进行配合,我们只是通过一些方式跳过了浏览器的阻拦。

对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。

CORS(Cross-Origin Resource Sharing, 跨域资源共享)的思想是浏览器和服务端通过头部信息来进行沟通确认是否给予响应。如:

Origin: http://www.baidu.com    // 浏览器的头部信息

// 如果服务端认可这个域名的跨域请求,如下设置就可跨域访问资源
Access-Control-Allow-Origin: http://www.baidu.com

如上就可以实现最简单的跨域访问,但是此时不能携带任何的cookie,如果我们需要传递cookie进行身份认证,需要设置:

xhr.withCredentials = true;    // 浏览器端
Access-Control-Allow-Credentials: true;    // 服务端

这样我们就可以传递认证信息了,但如果允许认证,Access-Control-Allow-Origin不能设置为*,而一定是具体的域名信息。

现在的浏览器都对CORS有了实现,如IE使用XDomainRequest对象,其它浏览器使用XMLHttpRequest对象。所以在此之前有很多奇技淫巧,如通过jsonp/图像 Ping方法都不再详述,而且其都需要服务端配合并且有很多局限性。

IE实现: XDomainRequest

var xdr = new XDomainRequest();
xdr.open('get', 'http://www.site.com/page');
xdr.send(null);

XDR区别于普通XHR:

  • 不能传输cookie

  • 只能设置请求头部的content-type

  • 不能访问响应头部信息

  • 只支持get/post方法

通过这些区别可以阻止一部分的CSRF(Cross-Site Request Forgery,跨站点请求伪造)XSS(Cross-Site Scripting,跨站点脚本)

XDR与XHR的使用上非常相似,区别有几点:

  • open()方法只接受两个参数,请求类型和URL

  • 只允许异步请求

  • 响应完成触发onload()事件,但我们只能访问responseText原始文本,并且无法获取响应的status.

  • 异常事件都会触发error事件,并且无错误信息可用。

其余浏览器实现: XMLHttpRequest

其余浏览器通过XHR对象直接实现了CORS,你只需要做的就是open()方法中传入一个绝对URL。

xhr.open('get', 'http://www.site.com/page', true);

相对于普通的XHR对象,CORS-XHR依然有部分限制:

  • 不能使用setRequestHeader()定义头部

  • 不能传递cookie

  • 调用getAllResponseHeaders(),结果为空

其余跨域方法

上面的两种方法已经很成熟了,但是仍然有一部分方法可以跨域,比如图像Ping

var img = new Image();
img.onload = img.onerror = function () {
    console.log('done');
}
img.src = 'http://www.site.com/test?name=Nicholas';

这种方式常用于服务端统计广告的点击次数,其缺陷为:

  • 只能是GET请求

  • 单向通信,无法获取响应文本

另外还有JSONP

function handleResponse(response) {
    console.log(response.ip, response.city);
}

var script = document.createElement('script');
script.src = 'http://freegeoip.net/json?callback=handleResponse';
document.body.insertBefore(script, document.body.firstChild);

这种方式通过和服务器配合,跨域请求一个js文件并被服务器处理后传回:

handleResponse({'name': 'Nicholas'});

然后直接在浏览器调用了该函数,传回的数据被当做response形参进行处理。但它也有一些缺陷:

  • 访问的方式是请求js,所以如果域名不安全,则很容易被恶意代码直接执行并攻击

  • 无法检测是否错误,因为js不支持这样的接口事件,只能超时判断

上面两种方式很容易看出,我们在支持CORS之前,使用的方法只不过是采用img/css/js等不受跨域访问限制的对象,变相拿到了响应数据,但都有缺陷,所以如果没有历史包袱,建议采用XDR或XHR对象来实现跨域访问。

XHR的兼容性

我们可以直接到Can I use这个网站上查询兼容性问题:
Principes AJAX et méthodes inter-domaines CORS


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!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn