Ajax and FETCH API details

  1. XMLHTTPRequest

  2. fetch

  • Cookies are not included by default
  • Error does not reject
  • Timeout Settings are not supported
  • AbortController is needed to abort fetch

Common browser request/response headers/error code parsing

request header

:method: GET :path: /solar-comment/api/comment/tutor-primary-activity/senior-recommend/users/self? tagSource=&_productId=351&_appId=0
:scheme: https
accept: application/json, text/plain, */* accept-encoding: gzip, deflate, br cache-control: no-cache cookie: deviceId=c122305d338525616baea870cc76dd5b; abSeed=843447469b71b0978db580220c952c10; userid=172270653; persistent=3411agNdImBJd8GjTW6bWT9Vg0U2yoaka3Lp8sSCiv9B6MDvr27fL4o50ha+Pfuhi1y4/Gg8aRN3FEP+VV4jWA==; sid=5530384168693043754; sess=QvrAQ0Cq+EcDQQPTer2XHlv4fhIRaW/YCb/e4pz/I+vzKp85mI2ukPUBIuGweXj5sq8HhuYQtf03DxK4dphwkOyBKovyUyC5I8t9exQw6Aw= origin: https://m.yuanfudao.biz referer: https://m.yuanfudao.biz/primary/market/senior-recommend/reserve 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.1Copy the code

response header

access-control-allow-credentials: true
access-control-allow-origin: https://m.yuanfudao.bizcontent-encoding: gzip content-type: application/json; charset=UTF- 8 -
date: Thu, 06 Aug 2020 08:15:05GMT set-cookie: sess=QvrAQ0Cq+EcDQQPTer2XHlv4fhIRaW/YCb/e4pz/I+uSfZtum4dPp9q4HJL5o+GWuDXHXQLQF2JrIgwzZPaZHWal4qYZy/cfW0Sle/fyB/w=; domain=.yuanfudao.biz; path=/; HttpOnly set-cookie: userid=172270653; domain=.yuanfudao.biz; path=/; HttpOnly status:200
Copy the code

status

200 Get succeeded 201 POST succeeded 301 Permanent Redirection 302 Temporary redirection 304 Negotiated cache server file is not modified 400 The client request has a syntax error and cannot be recognized by the server 403 The server receives the request but refuses to provide services. The resource requested across the domain 404 does not exist. The method requested by the 405 does not allow the 500 server to have unexpected errors

An example of sending a request and encapsulating a multi-browser-compatible request function

XMLHTTPRequest

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();
Copy the code

fetch

fetch(
        'http://domain/service', {
            method: 'GET'
        }
    )
    .then(response= > response.json())
    .then(json= > console.log(json))
    .catch(error= > console.error('error:', error));

// No cookies by default

fetch(
    'http://domain/service', {
        method: 'GET'.credentials: 'same-origin'})// Error not reject
// HTTP errors such as 404 Page Not Found or 500 Internal Server Error do Not cause the Fetch to return a Promise marked REJECT; .catch() is also not executed.
// To accurately determine whether the fetch is successful, include the promise resolved situation, and then determine whether response.ok is 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));

// It is not supported to set the timeout directly, use promise
function fetchTimeout(url, init, timeout = 3000) {
    return new Promise((resolve, reject) = > {
        fetch(url, init)
            .then(resolve)
            .catch(reject);
        setTimeout(reject, timeout); })}/ / suspend the 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();
Copy the code

Try wrapping request methods in TypeScript

interface IOptions {
    url: string; type? : string; data: any; timeout? : number; }function formatUrl(json) {
    let dataArr = [];
    json.t = Math.random();
    for (let key in json) {
        dataArr.push(`${key}=The ${encodeURIComponent(json[key])}`)}return dataArr.join('&');
}

export function ajax(options: IOptions) {
    return new Promise((resolve, reject) = > {
        if(! options.url)return;

        options.type = options.type || 'GET';
        options.data = options.data || {};
        options.timeout = options.timeout || 10000;
    
        let dataToUrlstr = formatUrl(options.data);
        let timer;
    
        / / 1. To create
        let xhr;
        if ((window as any).XMLHttpRequest) {
            xhr = new XMLHttpRequest();
        } else {
            xhr = new ActiveXObject('Microsoft.XMLHTTP');
        }
    
        if (options.type.toUpperCase() === 'GET') {
            / / 2. The connection
            xhr.open('get'.`${options.url}?${dataToUrlstr}`.true);
            / / 3. Send
            xhr.send();
        } else if (options.type.toUpperCase() === 'POST') {
            / / 2. The connection
            xhr.open('post', options.url, true);
            xhr.setRequestHeader('ContentType'.'application/x-www-form-urlencoded');
            / / 3. Send
            xhr.send(options.data);
        }
    
        / / 4. Receive
        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); }}}if (options.timeout) {
            timer = setTimeout(() = > {
                xhr.abort();
                reject('timeout');
            }, options.timeout)
        }

        // xhr.timeout = options.timeout;
        // xhr.ontimeout = () => {
        // reject(' reject ');
        // }
    });
}
Copy the code