Java learning notes -- AJAX&Fetch API

Posted by GetReady on Mon, 17 Jan 2022 06:45:04 +0100

What is AJAX?

AJAX is Asynchronous JavaScript And XML. Simply put, it uses the XMLHttpRequest object to communicate with the server. It can send and receive data in JSON, XML, HTML and text formats. The most attractive thing about AJAX is its "asynchronous" feature, that is, it can communicate with the server, exchange data, or update the page without refreshing the page.

Through interactive websites and modern Web standards, AJAX is gradually being replaced by functions in the JavaScript framework and the official Fetch API standard.

XMLHTTPRequest

The XMLHttpRequest (XHR) object is used to interact with the server. With XMLHttpRequest, you can request a specific URL to get data without refreshing the page. This allows the web page to update the local content of the page without affecting the user's operation. XMLHttpRequest is widely used in AJAX programming.

let xhr = new XMLHttpRequest();
xhr.open('GET', 'http://domain/service');

// request state change event
xhr.onreadystatechange = function () {
    // request completed?
    if (xhr.readyState !== 4) return;

    if (xhr.status === 200) {
        // request successful - show response
        console.log(xhr.responseText);
    } else {
        // request error
        console.log('HTTP error', xhr.status, xhr.statusText);
    }
};
// xhr.timeout = 3000; // 3 seconds
// xhr.ontimeout = () => console.log('timeout', xhr.responseURL);

// The progress event can report long-running file uploads
// xhr.upload.onprogress = p => {
//     console.log(Math.round((p.loaded / p.total) * 100) + '%');
// }

// start request
xhr.send();

All readyState state values are in XMLHttpRequest ReadyState, as follows:

  • 0 UNSENT Client has been created. open() not called yet.
  • 1 OPENED open() has been called.
  • 2 HEADERS_RECEIVED send() has been called, and headers and status are available. (the server has received the request)
  • 3 LOADING Downloading; responseText holds partial data. (the server is processing the request)
  • 4 DONE The operation is complete.

Fetch API

grammar

Promise<Response> fetch(url[, option]);

parameter

  • URL: URL string or a Request object
  • option optional, a configuration item object

    • Method: the method used in the request, such as GET and POST.
    • headers: request header information
    • Body: requested body information
    • Mode: the requested mode, such as cors, no cors, or same origin.
    • Credentials: the requested credentials, such as omit, same origin, or include. This option must be provided in order to automatically send cookies within the current domain name. Because cookies are not carried by default.
    • Cache: requested cache mode: default, no store, reload, no cache, force cache or only if cached.
    • signal: an AbortSignal object instance that allows you to communicate with the fetch request and abort it through the AbortController when needed.

Use example

  1. HTTP errors (such as 404 Page Not Found or 500 Internal Server Error) will not cause the Promise returned by fetch to be marked as reject, so the catch method will not be executed. To accurately judge whether the fetch is successful, you need to include the case of promise resolved, and then judge the response Is OK true

    fetch('http://domain/service', {
        method: 'GET'
        })
        .then(response => {
            if (response.ok) {
                return response.json();
            }
            throw new Error('Network response was not ok.');
        })
        .then(json => console.log(json))
        .catch(error => console.error('error:', error));
  2. fetch does not support setting timeout. promise is required

    function fetchTimeout(url, init, timeout = 3000) {
        return new Promise((resolve, reject) => {
            fetch(url, init)
                .then(resolve)
                .catch(reject);
            setTimeout(reject, timeout);
        })
    }
  3. Terminate fetch

    const controller = new AbortController();
    
    fetch(
            'http://domain/service', {
                method: 'GET',
                signal: controller.signal
            })
        .then(response => response.json())
        .then(json => console.log(json))
        .catch(error => console.error('Error:', error));
    
    controller.abort();

be careful:
xhr callback is a macro task, fetch is implemented based on promise, and its callback is a micro task

Common HTTP request header / response header / status code

request header

  • :method: GET
  • :path:
  • :scheme: https
  • accept: application/json, text/plain, /
  • accept-encoding: gzip, deflate, br
  • cache-control: no-cache
  • cookie: deviceId=c12;
  • origin:
  • referer:
  • user-agent: Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1

response header

  • access-control-allow-credentials: true
  • access-control-allow-origin:
  • content-encoding: gzip
  • content-type: application/json;charset=UTF-8
  • date: Thu, 06 Aug 2020 08:15:05 GMT
  • set-cookie: sess=QvrAQ0Cq+EcDQQPTer2X;
  • status: 200

status

  • 200 get succeeded
  • 201 post succeeded
  • 301 permanent redirection
  • 302 temporary redirection
  • 304 negotiation cache server file not modified
  • The 400 client request has syntax error and cannot be recognized by the server
  • 403 the server was requested but refused to provide service, possibly cross domain
  • 404 the requested resource does not exist
  • 405 the requested method is not allowed
  • An unexpected error occurred on the 500 server

Encapsulates a cross browser compatible request function

interface IOptions {
    url: string;
    type?: "GET" | "POST";
    data: any;
    timeout?: number;
}

function formatUrl(object) {
    // a=xxx&b=xxxx; querystring
    let dataArr = [];

    for (let key in object) {
        dataArr.push(`${key}=${encodeURIComponent(object[key])}`);
    }
    return dataArr.join("&");
}

export function ajax(
    options: IOptions = {
        type: "GET",
        data: {},
        timeout: 3000,
        url: "",
    }
) {
    return new Promise((resolve, reject) => {
        if (!options.url) {
            return;
        }

        const queryString = formatUrl(options.data);

        const onStateChange = () => {
            xhr.onreadystatechange = () => {
                if (xhr.readyState === 4) {
                    clearTimeout(timer);
                    if (
                        (xhr.status >= 200 && xhr.status < 300) ||
                        xhr.status === 304
                    ) {
                        resolve(xhr.responseText);
                    } else {
                        reject(xhr.status);
                    }
                }
            };
        };

        let timer;
        let xhr;

        if ((window as any).XMLHttpRequest) {
            xhr = new XMLHttpRequest();
        } else {
            xhr = new ActiveXObject("Microsoft.XMLHTTP");
        }

        if (options.type.toUpperCase() === "GET") {
            xhr.open("GET", `${options.url}?${queryString}`);
            onStateChange();
            xhr.send();
        } else if (options.type.toUpperCase() === "POST") {
            xhr.open("POST", options.url);
            xhr.setRequestHeader(
                "ContentType",
                "application/x-www-form-urlencoded"
            );
            onStateChange();
            xhr.send(options.data);
        }

        if (options.timeout) {
            timer = setTimeout(() => {
                xhr.abort();
                reject("timeout");
            }, options.timeout);
        }
    });
}

Topics: Ajax fetch