YYGod0120
XHRvsFetchCategories: Technology   2024-03-17

preface

During this period of time working on the AI-QA platform, I encountered a business requirement for GPT like post streaming response: by sending post issues to the backend, the backend adopts streaming response, which means returning data in segments and then rendering the style. I encountered a problem here, Axios cannot respond to post streaming.

On the contrary, native fetch can achieve post streaming processing.

1//核心代码
2async function run() {
3  aborter.abort(); // cancel previous request
4  outputEl.innerText = "";
5  aborter = new AbortController();
6  const prompt = new FormData(formEl).get("prompt");
7  try {
8    const response = await fetch("http://192.168.223.26:5000/chain", {
9      signal: aborter.signal,
10      method: "POST",
11      headers: { "Content-Type": "application/json" },
12      body: JSON.stringify({
13        prompt,
14      }),
15    });
16    const reader = response.body.getReader();
17    const decoder = new TextDecoder();
18    while (true) {
19      const { done, value } = await reader.read();
20      if (done) {
21        break;
22      }
23      const decoded = decoder.decode(value, { stream: true });
24      console.log(decoded);
25      outputEl.innerText += decoded;
26    }
27  } catch (err) {
28    console.error(err);
29  }
30}
31

So I went to check the relevant information and found thatAxiosIt seems that some places are really inferiorFetch

XHR(XMLHttpRequests)

AxiosIt is based onPromiseThe network request library uses the built-in HTTP module of Node.js on the node side and XMLHttpRequests on the browser side. Its functions include but are not limited to intercepting requests and responses, automatically converting JSON data, and canceling requests.

More content can be viewed directlyOfficial website.

What is the main topic hereXHR(XMLHttpRequests):

XHR is an early browser built-in object that, although named XML, can not only manipulate data in XML format, but also other data such as images, documents, and so on. But with the emergence of the updated fetch, XHR gradually disappeared, and the only reason it remained is probably to be compatible with old browsers, adapt to old scripts, and track upload progress (which fetch cannot do).

Fundamentals of XMLHttpRequests

XMLHttpRequest has two execution modes: synchronous and asynchronous

Let's first take a look at the most commonly used asynchronous:

1. CreateXMLHttpRequest

1let xhr = new XMLHttpRequest();
2

2. Initialize it

1xhr.open(method, URL, [async, user, password]);
2
  • Method - HTTP method. Usually it is "GET" or "POST".
  • URL - The URL to be requested, usually a string or a URL object.
  • Asynchronous - If explicitly set to false, the request will be processed synchronously, which we will discuss later.
  • User, password - The login name and password for HTTP basic authentication (if required).

3. Send a request

1xhr.send([body]);
2

4. Monitor XHR events to obtain responses

  • Load - When the request is completed (even if the HTTP status is 400 or 500, etc.) and the response has been fully downloaded.
  • Error - When a request cannot be made, such as a network interruption or an invalid URL.
  • Progress - Regularly triggered during the download response period, reporting how much has been downloaded.
1xhr.onload = function () {
2  alert(`Loaded: ${xhr.status} ${xhr.response}`);
3};
4
5xhr.onerror = function () {
6  // 仅在根本无法发出请求时触发
7  alert(`Network Error`);
8};
9
10xhr.onprogress = function (event) {
11  // 定期触发
12  // event.loaded —— 已经下载了多少字节
13  // event.lengthComputable = true,当服务器发送了 Content-Length header 时
14  // event.total —— 总字节数(如果 lengthComputable 为 true)
15  alert(`Received ${event.loaded} of ${event.total}`);
16};
17

Typical code for XHR Get request (probably not needed now):

1let xhr = new XMLHttpRequest();
2
3xhr.open("GET", "/my/url");
4
5xhr.send();
6
7xhr.onload = function () {
8  if (xhr.status != 200) {
9    // HTTP error?
10    // 处理 error
11    alert("Error: " + xhr.status);
12    return;
13  }
14
15  // 获取来自 xhr.response 的响应
16};
17
18xhr.onprogress = function (event) {
19  // 报告进度
20  alert(`Loaded ${event.loaded} of ${event.total}`);
21};
22
23xhr.onerror = function () {
24  // 处理非 HTTP error(例如网络中断)
25};
26

Upload Progress

As mentioned earlier, XML can track upload progress in a way that Fetch cannot - xhr.upload

It generates events, similar to XHR, but XHR. upload only triggers them when uploading:

  • Loadstart - Upload begins.
  • Progress - Regularly triggered during upload period.
  • Abort - Upload aborted.
  • Error - Non HTTP error.
  • Load - Upload successfully completed.
  • Timeout - upload timeout (if timeout property is set).
  • Loadend - Upload completed, regardless of success or error.

Example:

1xhr.upload.onprogress = function (event) {
2  alert(`Uploaded ${event.loaded} of ${event.total} bytes`);
3};
4
5xhr.upload.onload = function () {
6  alert(`Upload finished successfully.`);
7};
8
9xhr.upload.onerror = function () {
10  alert(`Error during the upload: ${xhr.status}`);
11};
12

Fetch

Fetch is a modern and universal JS network request method

Its advantages lie in:

  • Support asynchronous/await
  • Easy to write and user-friendly API
  • Detached from XHR, it is an implementation method in the ES specification

But it still has its drawbacks:

  • Browser not supported, polyfill required
  • Default no cookies
  • HTTP errors will not cause Promise to return reject
  • Not supporting viewing upload progress
  • Do not support timeout control

Next, let's take a look at the relevant process of Fetch

Fetch Fundamentals

Basic grammar:

1let promise = fetch(url, [options]);
2

The browser immediately initiates the request and returns a promise that the calling code should be used to obtain the result. Obtaining a response usually requires two stages.

In the first stage, when the server sends a response header, the promise returned by fetch uses the built-in Response class object to parse the response header.

At this stage, we can confirm whether the request is successful by checking the status of the response header. If the fetch cannot be successfully established, that is, if there are network problems or other network issues, the promise will be rejected.

Therefore, all server returns such as 404 or 500 will not cause Promise to return reject, making it difficult to track errors.

In the second stage, in order to obtain the response body, we need to call another method.

Response provides multiple promise based methods to access the body in different formats:

  • Response. text() - Read the response and return it in text format,

  • Response. json () - parses the response into JSON format,

  • Response. formData() - returns a response in the form of a FormData object (explained in the next chapter),

  • Response. blob() - returns a response in the form of a Blob (binary data with a type),

  • Response. arrayBuffer() - returns the response in the form of an ArrayBuffer (low-level binary data),

    In addition, responsive.body is a ReadableStream object that allows you to read the body block by block. The GPTpost response stream is based on this for streaming responses:

1const response = await fetch("http://192.168.223.26:5000/chain", {
2  signal: aborter.signal,
3  method: "POST",
4  headers: { "Content-Type": "application/json" },
5  body: JSON.stringify({
6    prompt,
7  }),
8});
9const reader = response.body.getReader();
10

We can only choose one method to read the body. If we have already used the response. text() method to obtain the response, then using response. json () will not take effect because the body content has already been processed.

other

XML: Extensible Markup Language (XML) is a markup language. XML is simplified and modified from Standard Generalized Markup Language (SGML).

AJAX (Asynchronous JavaScript And XML) is a programming practice that uses XMLHttpRequest technology to build more complex and dynamic web pages. The implementation methods include the ancient XHR and the new Fetch.

HTTP module: The HTTP module refers to the HTTP module in the node, including:

  • Http.create Server serves as the web server
  • http.createClient, Serve as a client and implement tasks such as crawling.
© 2023 - 2024
githubYYGod0120