Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Analyze the network request mode of web front end

2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article introduces the relevant knowledge of "analyzing the network request mode of the web front end". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

First, the focus of the front-end network request

In most cases, to initiate a network request at the front end, we only need to focus on the following points:

Pass in basic parameters (url, request method)

Request parameters, request parameter types

Set request header

How to get the response

Get response header, response status, response result

Exception handling

Carry cookie settings

Cross-domain request

Second, the way the front end makes the network request

Form forms, ifream, refresh pages

Ajax-the originator of asynchronous network requests

JQuery-an era

The replacement of fetch-Ajax

Axios, request and many other open source libraries

Third, questions about network requests

What problems have been solved by the emergence of Ajax

How to use native Ajax

The network request mode of jQuery

The usage and pitfalls of fetch

How to use fetch correctly

How to choose the appropriate cross-domain approach

With the above questions and concerns, we make a comprehensive analysis of several network requests.

4. What problems have been solved by the emergence of Ajax

Before Ajax, the web program worked like this:

The drawback of this interaction is obvious, any interaction with the server needs to refresh the page, the user experience is very poor, the emergence of Ajax solves this problem. Ajax full name Asynchronous JavaScript + XML (Asynchronous JavaScript and XML)

With Ajax, web applications can quickly render incremental updates to the user interface without reloading (refreshing) the entire page.

Ajax itself is not a new technology, but is used to describe a technical solution implemented using a collection of existing technologies, and the browser's XMLHttpRequest is the most important object for implementing Ajax (ActiveXObject is used below IE6).

Although X stands for XML in Ajax, JSON is currently more commonly used than XML because of many of the advantages of JSON, such as being lighter and as part of Javascript.

Fifth, the usage of native Ajax

Here is the main analysis of the XMLHttpRequest object, here is a section of its basic use:

Var xhr = new XMLHttpRequest (); xhr.open ('post','www.xxx.com',true) / / receive the return value xhr.onreadystatechange = function () {if (xhr.readyState = 4) {if (xhr.status > = 200 & & xhr.status)

< 300) || xhr.status == 304){ console.log(xhr.responseText); } } } // 处理请求参数 postData = {"name1":"value1","name2":"value2"}; postData = (function(value){ var dataString = ""; for(var key in value){ dataString += key+"="+value[key]+"&"; }; return dataString; }(postData)); // 设置请求头 xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded"); // 异常处理 xhr.onerror = function() { console.log('Network request failed') } // 跨域携带cookie xhr.withCredentials = true; // 发出请求 xhr.send(postData); 下面分别对XMLHttpRequest对象常用的的函数、属性、事件进行分析。 函数 open 用于初始化一个请求,用法: xhr.open(method, url, async); method:请求方式,如get、post url:请求的url async:是否为异步请求 send 用于发送 HTTP 请求,即调用该方法后HTTP请求才会被真正发出,用法: xhr.send(param) param:http请求的参数,可以为string、Blob等类型。 abort 用于终止一个ajax请求,调用此方法后readyState将被设置为0,用法: xhr.abort() setRequestHeader 用于设置HTTP请求头,此方法必须在 open() 方法和 send() 之间调用,用法: xhr.setRequestHeader(header, value); getResponseHeader 用于获取http返回头,如果在返回头中有多个一样的名称,那么返回的值就会是用逗号和空格将值分隔的字符串,用法: var header = xhr.getResponseHeader(name); 属性 readyState 用来标识当前XMLHttpRequest对象所处的状态,XMLHttpRequest对象总是位于下列状态中的一个: 值状态描述0UNSENT代理被创建,但尚未调用 open() 方法。1OPENEDopen() 方法已经被调用。2HEADERS_RECEIVEDsend() 方法已经被调用,并且头部和状态已经可获得。3LOADING下载中; responseText 属性已经包含部分数据。4DONE下载操作已完成。 status 表示http请求的状态, 初始值为0。如果服务器没有显式地指定状态码, 那么status将被设置为默认值, 即200。 responseType 表示响应的数据类型,并允许我们手动设置,如果为空,默认为text类型,可以有下面的取值: 值描述""将 responseType 设为空字符串与设置为"text"相同, 是默认类型 (实际上是 DOMString)。"arraybuffer"response 是一个包含二进制数据的 JavaScript ArrayBuffer 。"blob"response 是一个包含二进制数据的 Blob 对象 。"document"response 是一个 HTML Document 或 XML XMLDocument ,这取决于接收到的数据的 MIME 类型。"json"response 是一个 JavaScript 对象。这个对象是通过将接收到的数据类型视为 JSON 解析得到的。"text"response 是包含在 DOMString 对象中的文本。 response 返回响应的正文,返回的类型由上面的responseType决定。 withCredentials ajax请求默认会携带同源请求的cookie,而跨域请求则不会携带cookie,设置xhr的withCredentials的属性为true将允许携带跨域cookie。 事件回调 onreadystatechange xhr.onreadystatechange = callback; 当readyState 属性发生变化时,callback会被触发。 onloadstart xhr.onloadstart = callback; 在ajax请求发送之前(readyState==1后, readyState==2前),callback会被触发。 onprogress xhr.onprogress = function(event){ console.log(event.loaded / event.total); } 回调函数可以获取资源总大小total,已经加载的资源大小loaded,用这两个值可以计算加载进度。 onload xhr.onload = callback; 当一个资源及其依赖资源已完成加载时,将触发callback,通常我们会在onload事件中处理返回值。 异常处理 onerror xhr.onerror = callback; 当ajax资源加载失败时会触发callback。 ontimeout xhr.ontimeout = callback; 当进度由于预定时间到期而终止时,会触发callback,超时时间可使用timeout属性进行设置。 六、jQuery对Ajax的封装 在很长一段时间里,人们使用jQuery提供的ajax封装进行网络请求,包括$.ajax、$.get、$.post等,这几个方法放到现在,我依然觉得很实用。 $.ajax({ dataType: 'json', // 设置返回值类型 contentType: 'application/json', // 设置参数类型 headers: {'Content-Type','application/json'},// 设置请求头 xhrFields: { withCredentials: true }, // 跨域携带cookie data: JSON.stringify({a: [{b:1, a:1}]}), // 传递参数 error:function(xhr,status){ // 错误处理 console.log(xhr,status); }, success: function (data,status) { // 获取结果 console.log(data,status); } }) $.ajax只接收一个参数,这个参数接收一系列配置,其自己封装了一个jqXHR对象,有兴趣可以阅读一下jQuary-ajax 源码 常用配置: url 当前页地址。发送请求的地址。 type 类型:String 请求方式 ("POST" 或 "GET"), 默认为 "GET"。注意:其它 HTTP 请求方法,如 PUT 和 DELETE 也可以使用,但仅部分浏览器支持。 timeout 类型:Number 设置请求超时时间(毫秒)。此设置将覆盖全局设置。 success 类型:Function 请求成功后的回调函数。 jsonp 在一个jsonp请求中重写回调函数的名字。这个值用来替代在"callback=?"这种GET或POST请求中URL参数里的"callback"部分。 error 类型:Function 。请求失败时调用此函数。 注意:源码里对错误的判定: isSuccess = status >

& & status

< 300 || status === 304; 返回值除了这几个状态码都会进error回调。 dataType "xml": 返回 XML 文档,可用 jQuery 处理。 "html": 返回纯文本 HTML 信息;包含的 script 标签会在插入 dom 时执行。 "script": 返回纯文本 JavaScript 代码。不会自动缓存结果。除非设置了 "cache" 参数。注意:在远程请求时(不在同一个域下),所有 POST 请求都将转为 GET 请求。(因为将使用 DOM 的 script标签来加载) "json": 返回 JSON 数据 。 "jsonp": JSONP 格式。使用 JSONP 形式调用函数时,如 "myurl?callback=?" jQuery 将自动替换 ? 为正确的函数名,以执行回调函数。 "text": 返回纯文本字符串 data 类型:String 使用JSON.stringify转码 complete 类型:Function 请求完成后回调函数 (请求成功或失败之后均调用)。 async 类型:Boolean 默认值: true。默认设置下,所有请求均为异步请求。如果需要发送同步请求,请将此选项设置为 false。 contentType 类型:String 默认值: "application/x-www-form-urlencoded"。发送信息至服务器时内容编码类型。 键值对这样组织在一般的情况下是没有什么问题的,这里说的一般是,不带嵌套类型JSON,也就是 简单的JSON,形如这样: { a: 1, b: 2, c: 3 } 但是在一些复杂的情况下就有问题了。 例如在 Ajax 中你要传一个复杂的 json 对像,也就说是对象嵌数组,数组中包括对象,你这样传: application/x-www-form-urlencoded 这种形式是没有办法将复杂的 JSON 组织成键值对形式。 { data: { a: [{ x: 2 }] } } 可以用如下方式传递复杂的json对象 $.ajax({ dataType: 'json', contentType: 'application/json', data: JSON.stringify({a: [{b:1, a:1}]}) }) 七、jQuery的替代者 近年来前端MV*的发展壮大,人们越来越少的使用jQuery,我们不可能单独为了使用jQuery的Ajax api来单独引入他,无可避免的,我们需要寻找新的技术方案。 尤雨溪在他的文档中推荐大家用axios进行网络请求。axios基于Promise对原生的XHR进行了非常全面的封装,使用方式也非常的优雅。另外,axios同样提供了在node环境下的支持,可谓是网络请求的重要方案。 未来必定还会出现更优秀的封装,他们有非常周全的考虑以及详细的文档,这里我们不多做考究,我们把关注的重点放在更底层的APIfetch。 Fetch API 是一个用用于访问和操纵HTTP管道的强大的原生 API。 这种功能以前是使用 XMLHttpRequest实现的。Fetch提供了一个更好的替代方法,可以很容易地被其他技术使用,例如 Service Workers。Fetch还提供了单个逻辑位置来定义其他HTTP相关概念,例如CORS和HTTP的扩展。 可见fetch是作为XMLHttpRequest的替代品出现的。 使用fetch,你不需要再额外加载一个外部资源。但它还没有被浏览器完全支持,所以你仍然需要一个 polyfill。 八、fetch的使用 一个基本的 fetch请求: const options = { method: "POST", // 请求参数 headers: { "Content-Type": "application/json"}, // 设置请求头 body: JSON.stringify({name:'123'}), // 请求参数 credentials: "same-origin", // cookie设置 mode: "cors", // 跨域 } fetch('http://www.xxx.com',options) .then(function(response) { return response.json(); }) .then(function(myJson) { console.log(myJson); // 响应数据 }) .catch(function(err){ console.log(err); // 异常处理 }) Fetch API提供了一个全局的fetch()方法,以及几个辅助对象来发起一个网络请求。 fetch() fetch()方法用于发起获取资源的请求。它返回一个 promise,这个 promise 会在请求响应后被 resolve,并传回 Response 对象。 Headers 可以通过 Headers() 构造函数来创建一个你自己的 headers 对象,相当于 response/request 的头信息,可以使你查询到这些头信息,或者针对不同的结果做不同的操作。 var myHeaders = new Headers(); myHeaders.append("Content-Type", "text/plain"); Request 通过 Request() 构造函数可以创建一个Request 对象,这个对象可以作为fetch函数的第二个参数。 Response 在fetch()处理完promises之后返回一个Response 实例,也可以手动创建一个Response实例。 九、fetch polyfill源码分析 由于fetch是一个非常底层的API,所以我们无法进一步的探究它的底层,但是我们可以借助它的polyfill探究它的基本原理,并找出其中的坑点。 代码结构 由代码可见,polyfill主要对Fetch API提供的四大对象进行了封装: fetch 封装

The code is very clear:

Construct a Promise object and return

Create a Request object

Create a XMLHttpRequest object

Take the request url in the Request object, send it to the requester, open a xhr request, and assign the headers stored in the Request object to the xhr

After xhr onload, take out the status, headers and body of response to encapsulate Response objects, and call resolve.

Exception handling

As you can see, there are three possibilities for calling reject:

1. Request timeout

two。 Request failed

Note: when establishing a profile with the server and receiving the server's abnormal status codes such as 404,500, etc., onerror will not be triggered. When the network fails or the request is blocked, it will be marked as reject, such as cross-domain, url does not exist, network exception and so on will trigger onerror.

So using fetch will enter the then instead of the catch when receiving the exception status code. These error requests are often handled manually.

3. Manual termination

You can pass the signal object in the request parameter, and add abort event listeners to the signal object. When xhr.readyState becomes 4 (response content parsing is complete), remove the abort event listener from the signal object.

This means that a fetch request can be terminated by calling signal.abort before it ends. You can create a controller in the browser using the AbortController () constructor, and then use the AbortController.signal property

This is an experimental feature that some browsers are still developing

Headers encapsulation

A map object is maintained in the header object, and header of Header object, array, normal object type can be passed in the constructor, and all values are maintained into map.

You saw earlier in the fetch function that the forEach method of header was called. Here is its implementation:

It can be seen that the traversal of header is the traversal of its internal map.

In addition, Header also provides append, delete, get, set and other methods, all of which operate on its internal map objects.

Request object

The two parameters received by the Request object are the two parameters received by the fetch function, one parameter can be passed directly to url or a constructed request object, and the other parameter controls different configurations of option objects.

You can input attributes such as credentials, headers, method, mode, signal, referrer, and so on.

Note here:

The headers passed in is used as an argument to the Headers constructor to construct the header object.

Cookie processing

There is also the following code in the fetch function:

If (request.credentials = = 'include') {xhr.withCredentials = true} else if (request.credentials = =' omit') {xhr.withCredentials = false}

The default credentials type is same-origin, which allows you to carry the coodkie of the same origin request.

Then I found that the implementation of polyfill here is inconsistent with MDN- 's use of Fetch and a lot of information:

Mdn: by default, fetch does not send or receive any cookies from the server

So I experimented with using polyfill and using native fetch to carry cookie, and found that homologous cookie is carried by default without setting credentials, which is inconsistent with the description of the document. After consulting a lot of materials, it is said that fetch does not carry cookie by default. The following is the case of using native fetch to make requests in browsers:

Then I found that MDN-Fetch-Request had pointed out that the default value of the new browser credentials had been changed to same-origin, while the old version was still omit.

It is true that MDN- uses Fetch to update the documents here in a timely manner, which is a mistake to the children.

Response object

The Response object is the return value after a successful fetch call:

Review the operations on Response` in fetch:

Xhr.onload = function () {var options = {status: xhr.status, statusText: xhr.statusText, headers: parseHeaders (xhr.getAllResponseHeaders () | |')} options.url = 'responseURL' in xhr? Xhr.responseURL: options.headers.get ('XmurRequestMurURL') var body = 'response' in xhr? Xhr.response: xhr.responseText resolve (new Response (body, options))}

Response constructor:

It can be seen that in the constructor, status, statusText, headers and url in options are processed and mounted on the Response object respectively.

The constructor does not explicitly deal with responseText and leaves it to the _ initBody function, while Response does not actively declare the _ initBody attribute. The code uses Response to call the Body function. In fact, the _ initBody function is mounted to Response through the Body function. Let's take a look at the _ initBody function:

It can be seen that the _ initBody function assigns values to different parameters according to the type of xhr.response (Blob, FormData, String...). These parameters are applied differently in the Body method. Let's see what other operations the Body function has done:

The Body function also mounts four functions for the Response object, text, json, blob, and formData. The operation in these functions is to return the different types of return values obtained in _ initBody.

This also shows that after the execution of the fetch, the return value can not be obtained directly in the response, but must be called text (), json () and other functions to get the return value.

There is one more thing to note here: several functions have logic similar to the following:

Var rejected = consumed (this) if (rejected) {return rejected}

Consumed function:

Function consumed (body) {if (body.bodyUsed) {return Promise.reject (new TypeError ('Already read'))} body.bodyUsed = true}

After each call to functions such as text (), json (), and so on, the bodyUsed variable is changed to true to indicate that the return value has been read, and the next read throws TypeError ('Already read') directly. This also follows the principles of native fetch:

Because Responses objects are set to stream, they can only be read once

The potholes of fetch

Fetch is described in VUE's documentation as follows:

There are many other considerations when using fetch, which is why people still prefer axios at this stage. Of course, this may change in the future.

Because fetch is a very low-level API, it is not encapsulated much, and there are still many issues that need to be addressed:

Cannot pass a JavaScript object as a parameter directly

You need to judge the return value type and execute the response method to get the return value.

The method to get the return value can only be called once, not multiple times.

Unable to catch exceptions normally

Older browsers do not carry cookie by default

Jsonp is not supported

11. Encapsulation of fetch

Request parameter processing

Different parameter types are supported:

Function stringify (url, data) {var dataString = url.indexOf ('?') =-1?'?':'&'; for (var key in data) {dataString + = key +'='+ data [key] +'&;}; return dataString;} if (request.formData) {requestrequest.body = request.data } else if (/ ^ get$/i.test (request.method)) {request.url = `${request.url} ${stringify (request.url, request.data)}`;} else if (request.form) {request.headers.set ('Content-Type',' application/x-www-form-urlencoded;charset=UTF-8'); request.body = stringify (request.data);} else {request.headers.set ('Content-Type',' application/json;charset=UTF-8') Request.body = JSON.stringify (request.data);}

Cookie carrying

Fetch has been carried with homologous cookie by default in new browsers, but not by default in older browsers. We need to set it uniformly:

Request.credentials = 'same-origin'; / / homologous portability request.credentials =' include'; / / Cross-domain portability

Exception handling

When a HTTP status code representing an error is received, the Promise returned from fetch () is not marked as reject, even if the HTTP response has a status code of 404 or 500. Instead, it marks the Promise status as resolve (but sets the ok property of the return value of the resolve to false) and marks it as reject only if the network fails or the request is blocked.

Therefore, we need to handle the exceptions of fetch uniformly.

Then (response = > {if (response.ok) {return Promise.resolve (response);} else {const error = new Error (`request failed! Status code: ${response.status}, failure message: ${response.statusText} `); error.response = response; return Promise.reject (error);}})

Return value processing

Call different functions to receive different return value types. Here, the type must be judged in advance, and the method to obtain the return value cannot be called many times:.

Then (response = > {let contentType = response.headers.get ('content-type'); if (contentType.includes (' application/json')) {return response.json ();} else {return response.text ();}})

Jsonp

Fetch itself does not provide support for jsonp, and jsonp itself is not a very good way to solve cross-domain problems. It is recommended to use cors or nginx to solve cross-domain problems. For more information, please see the following section.

Fetch is packaged and can be used happily.

Well, axios works really well.

XII. Cross-domain summary

When it comes to network requests, you have to mention cross-domain.

The browser's same-origin policy limits how documents or scripts loaded from the same source interact with resources from another source. This is an important security mechanism for isolating potentially malicious files. Read operations between different sources are usually not allowed.

Cross-domain conditions: protocols, domain names, ports, there is a difference even if cross-domain.

Here are several ways to solve cross-domain problems:

Nginx

Use nginx reverse proxy to achieve cross-domain, refer to my article: nginx knowledge necessary for front-end developers

Cors

CORS is a W3C standard, the full name is "cross-domain resource sharing" (Cross-origin resource sharing). It allows browsers to make XMLHttpRequest requests to cross-source servers.

CORS can be enabled by setting Access-Control-Allow-Origin on the server. This attribute indicates which domain names can access the resource, and if you set a wildcard, it means that all websites can access the resource.

App.all ('*', function (req, res, next) {res.header ("Access-Control-Allow-Origin", "*"); res.header ("Access-Control-Allow-Headers", "X-Requested-With"); res.header ("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS"); next ();})

Jsonp

The link in the src attribute of the script tag can access cross-domain js scripts. Taking advantage of this feature, the server no longer returns data in JSON format, but returns a piece of js code that calls a function, which is called in src.

Jquery support for jsonp:

Ajax ({type: "get", url: "http://xxxx" dataType:" jsonp ", jsonp:" callback ", jsonpCallback:" doo ", success: function (data) {console.log (data);}})

Fetch, axios, etc., do not provide direct support for jsonp. If you need to use this method, you can try manual encapsulation:

(function (window,document) {"use strict"; var jsonp = function (url,data,callback) {/ / 1. Convert the incoming data data into url string form / / {id:1,name:'jack'} = > id=1&name=jack var dataString = url.indexof ('?) = =-1?':'&'; for (var key in data) {dataString + = key +'='+ data [key] +'&';} / / 2 handles the name of the callback function / / cbFuncName callback function in url: the prefix of the my_json_cb_ name + random number (remove the decimal point) var cbFuncName = 'my_json_cb_' + Math.random (). ToString (). Replace ('.','); dataString + = 'callback=' + cbFuncName; / / 3. Create a script tag and insert it into the page var scriptEle = document.createElement ('script'); scriptEle.src = url + dataString; / / 4. Mount the callback function window [cbFuncName] = function (data) {callback (data); / / delete jsonp's script tag document.body.removeChild (scriptEle);} document.body.appendChild (scriptEle);} window.$jsonpjsonp = jsonp;}) (window,document) after processing the callback function data

PostMessage cross-domain

The postMessage () method allows scripts from different sources to communicate in a limited way asynchronously, and messages can be delivered across text files, multiple windows, and across domains.

/ / capture iframe var domain = 'http://scriptandstyle.com'; var iframe = document.getElementById (' myIFrame'). ContentWindow; / / send the message setInterval (function () {var message = 'Hello! The time is:'+ (new Date (). GetTime ()); console.log ('blog.local: sending message:' + message); / / send the message and target URI iframe.postMessage (message,domain);}, 6000); / / response event window.addEventListener ('message',function (event) {if (event.origin! = =' http://davidwalsh.name') return) Console.log ('message received:' + event.data,event); event.source.postMessage ('holla back originals);}, false)

PostMessage is suitable for the following scenarios: cross-domain communication between multiple windows of the same browser, and cross-domain communication between iframe.

WebSocket

WebSocket is a two-way communication protocol. After establishing a connection, both server and client of WebSocket can actively send or receive data to each other without the restriction of the same origin policy.

Function WebSocketTest () {if ("WebSocket" in window) {alert ("your browser supports WebSocket!"); / / Open a web socket var ws = new WebSocket ("ws://localhost:3000/abcd") Ws.onopen = function () {/ / Web Socket is connected, use the send () method to send data ws.send ("send data"); alert ("data sending...");} Ws.onmessage = function (evt) {var received_msg = evt.data; alert ("data received...");}; ws.onclose = function () {/ / close websocket alert ("connection closed...") };} else {/ / browser does not support WebSocket alert ("your browser does not support WebSocket!");}} "analyzing the web request mode of the web front end" ends here. Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report