What is Fetch?

Fetch is a JavaScript interface, an ideal alternative to XMLHttpRequest, for asynchronously fetching resources (HTTP requests) across a network.

A basic FETCH request is simple to set up. Look at the following code:

fetch('http://example.com/movies.json')
  .then((response) => {
      return response.json();
  })
  .then((myJson) => {
    console.log(myJson);
  });
Copy the code

Dai Yu tong “come late” : I this time, after all or come too late

Just as a review XMLHttpRequest gets data (Ajax)

Step: 1. Create XmlHttpRequest object 2. Call open method to set basic request information 3. Set the data to send and send the request. 4. Register the callback function to listen to. 5

If (window.xmlHttprequest){var oAjax=new XMLHttpRequest(); }else{// compatible ie var oAjax=new ActiveXObject(" microsoft.xmlhttp "); Oajax.open ('GET', URL, true); //2. / / 3. Send oAjax. The send (); Onreadystatechange =function (){if(oajax.readystate ==4){if(oajax.status ==200){//alert(' successful: '+oAjax.responseText); fnSucc(oAjax.responseText); }else{//alert(' failed '); if(fnFaild){ fnFaild(); }}}};Copy the code

The fetch encapsulation

Fetch parameters (feach (URL, optionObj))

A POST request

const response = await fetch(url, {
  method: 'POST',
  headers: {
    "Content-type": "application/json; charset=UTF-8",
  },
  body: 'foo=bar&lorem=ipsum',
});

const json = await response.json();
Copy the code

The configuration object uses three properties

  • method: Method of HTTP request,POST,DELETE,PUTIt’s all in this property setting.
  • headers: An object that is used to customize the headers of HTTP requests.
  • body: The body of the POST request.

Some headers cannot be set via the headers property, such as content-length, Cookie, Host, and so on. They are automatically generated by the browser and cannot be modified.

Adding JSON Data

const user = { name: 'John', surname: 'Smith' }; const response = await fetch('/article/fetch/post/user', { method: 'POST', headers: { 'Content-Type': 'application/json; charset=utf-8' }, body: JSON.stringify(user) });Copy the code

Encapsulate a fetch of its own (forms not supported)

interface IInit extendsRequestInit { body? : BodyInit |null| any; prefix? :'api' | 'api1';
}
export default function fetch(url: string, init? : IInit) {
  if(! init) init = {};const prefix = init.prefix ? uPrefix[init.prefix] : uPrefix.api;

  if(! init.credentials) init.credentials ='include'; // By default, cookies are sent for both same-origin and cross-domain requests.
  if (init.body && typeof init.body === 'object') init.body = JSON.stringify(init.body); // Convert the JSON string
  if(init.body && ! init.method) init.method ='POST'; // There is a body, the default request method is POST
  if (init.method) init.method = init.method.toUpperCase(); // Convert the string to uppercase

  if (['POST'.'PUT'.'DELETE'].includes(init.method || ' ')) { // Submit JSON data, default is 'text/plain; charset=UTF-8'
    init.headers = Object.assign({}, init.headers || {
      'Content-Type': 'application/json'}); } init = addCustomHeader(init)const realUrl = `${prefix}${url}`;
  return window
    .fetch(realUrl, init)
    .then(res= > checkStatus(res)) // Check the response code
    .then((res) = > res.json())
    .then((res) = > filter(res)) // Filter based on service requirements
    .catch(err= > console.log('Request failed! + url:${realUrl}`, err));
}
Copy the code

fetch()Complete API for configuration objects

The full API for the second argument of fetch() is as follows.

const response = fetch(url, { method: "GET", headers: { "Content-Type": "text/plain; charset=UTF-8" }, body: undefined, referrer: "about:client", referrerPolicy: "no-referrer-when-downgrade", mode: "cors", credentials: "same-origin", cache: "default", redirect: "follow", integrity: "", keepalive: false, signal: undefined });Copy the code

cache

The cache property specifies how the cache is handled. Possible values are as follows:

  • default: the default value, which is used to look for matching requests in the cache.
  • no-store: Requests the remote server directly and does not update the cache.
  • reload: Requests the remote server directly and updates the cache.
  • no-cache: Compares server resources to the local cache. Use server resources only if there is a new version, otherwise use cache.
  • force-cache: Cache takes precedence. Request the remote server only if no cache exists.
  • only-if-cached: check only the cache, if the cache does not exist, return error 504.

mode

The mode attribute specifies the mode of the request. Possible values are as follows:

  • cors: The default value allows cross-domain requests.
  • same-origin: Only same-origin requests are allowed.
  • no-cors: Request methods are limited to GET, POST, and HEAD, and can only use a limited number of simple headers. You cannot add complex cross-domain headers, equivalent to the request that can be made by submitting a form.

credentials

The credentials attribute specifies whether to send cookies. Possible values are as follows:

  • same-origin: The default value. Cookie is sent for same-origin requests but not for cross-domain requests.
  • include: Cookie is sent regardless of the same origin request or cross-domain request.
  • omit: All do not send.

To send cookies for cross-domain requests, set the credentials attribute to include.


fetch('http://another.com', {
  credentials: "include"
});
Copy the code

signal

The signal property specifies an AbortSignal instance to cancel the fetch() request, as described in the next section.

keepalive

The Keepalive property is used when a page is uninstalled to tell the browser to stay connected in the background and continue sending data.

A typical scenario is when a user leaves a web page and the script submits some statistics about the user’s behavior to the server. At this point, without the Keepalive property, the data may not be sent because the browser has already uninstalled the page.


window.onunload = function() {
  fetch('/analytics', {
    method: 'POST',
    body: "statistics",
    keepalive: true
  });
};
Copy the code

redirect

The redirect attribute specifies how HTTP redirects are handled. Possible values are as follows:

  • follow: Default value,fetch()Follow the HTTP jump.
  • error: If a jump occurs,fetch()Is an error.
  • manual:fetch()Does not follow the HTTP jump, howeverresponse.urlProperty will point to the new URL,response.redirectedThe property will change totrue, it is up to the developer to decide how to handle the jump afterwards.

integrity

The integrity property specifies a hash value to check whether the data returned by the HTTP response is equal to the preset hash value.

For example, when downloading a file, check that the sha-256 hash of the file matches to make sure it hasn’t been tampered with.


fetch('http://site.com/file', {
  integrity: 'sha256-abcdef'
});
Copy the code

referrer

The referrer property is used to set the referer header for the fetch() request.

This property can be any string or it can be set to an empty string (that is, no referer header is sent).


fetch('/page', {
  referrer: ''
});
Copy the code

referrerPolicy

The referrerPolicy attribute is used to set the rules for the Referer header. Possible values are as follows:

  • no-referrer-when-downgrade: Default value, always sendRefererHeader, unless an HTTP resource is requested from an HTTPS page.
  • no-referrer: don’t sendRefererThe headers.
  • origin:RefererThe header contains only the domain name, not the full path.
  • origin-when-cross-origin: Same source requestRefererThe header contains the full path, and the cross-domain request contains only the domain name.
  • same-origin: The cross-domain request is not sentReferer, the same source request is sent.
  • strict-origin:RefererThe header contains only the domain name and is not sent when an HTTPS page requests HTTP resourcesRefererThe headers.
  • strict-origin-when-cross-origin: Same-origin requestRefererThe header contains the full path, only the domain name for cross-domain requests, and is not sent when an HTTPS page requests HTTP resources.
  • unsafe-url: Always send no matter whatRefererThe headers.

cancelfetch()request

If you want to cancel the fetch() request after it has been sent, you need to use the AbortController object.

let controller = new AbortController(); let signal = controller.signal; fetch(url, { signal: controller.signal }); signal.addEventListener('abort', () => console.log('abort! ')); controller.abort(); / / cancel the console. The log (signal. Aborted); // trueCopy the code

In the example above, the AbortController instance is created first and the fetch() request is sent. The signal property of the configuration object must specify that the AbortController instance is sent to receive controller.signal.

The controller.abort() method is used to signal cancellation. Will trigger the abort event at this moment, this event can listen, but can be by the controller. The signal. The aborted attribute to determine whether a cancellation signal has been issued.

Start building Axios

1. Clone the Demo project

    git clone https://gitee.com/dengruifeng/wabpack-demo
Copy the code

Establish the fetch. Ts

import { notification } from 'antd';

const window = self.window;
export interface IRes { // The format agreed with the backend
  code: number;
  message: string;
  data: any;
}

interface IInit extendsRequestInit { body? : BodyInit |null | any;
}

const checkStatus = (res: Response) = > {
  if (res.status === 401) {
    window.location.href = '/login';
  }

  if (res.status === 405 || res.status === 403) {
    location.href = '/ 403';
  }

  if (res.status === 404) {
    notification.error({ message: 'Interface does not exist' });
  }

  return res;
};

const filter = (res: IRes) = > {
  // if (res.code ! == 0 && res.code ! = = 200) {
  // notification.error({
  //     message: '错误',
  / / description: res. Message | | 'service error, please try again! ',
  / /});
  // throw res;
  // }
  res.data = res;
  return res.data; // Return the data
};

const addCustomHeader = (init? : IInit) = > { // Add a custom header
  init = init || {};
  init.headers = Object.assign(init? .headers || {}, {// 'X-SSO-USER': 'admin',
  });
  return init;
};

export default function fetch(url: string, init? : IInit) {
  if(! init) init = {};// if (! init.credentials) init.credentials = 'include'; // The default is same-origin, include. Cookie is sent regardless of the same origin request or cross-domain request.
  if (init.body && typeof init.body === 'object') init.body = JSON.stringify(init.body); // Convert the JSON string
  if(init.body && ! init.method) init.method ='POST'; // There is a body, the default request method is POST
  if (init.method) init.method = init.method.toUpperCase(); // Convert the string to uppercase

  if (['POST'.'PUT'.'DELETE'].includes(init.method || ' ')) { // Submit JSON data, default is 'text/plain; charset=UTF-8'
    init.headers = Object.assign({}, init.headers || {
      'Content-Type': 'application/json'}); } init = addCustomHeader(init);console.log(init);
  return window
    .fetch(url, init)
    .then(res= > checkStatus(res)) // Check the response code
    .then((res) = > res.json())
    .then((res) = > filter(res)) // Filter based on service requirements
    .catch(err= > console.log('Request failed! + url:${url}`, err));
}

export function formFetch(url: string, init? : IInit) { // Form fetch, used to upload files, etc
  if(! init) init = {}; init = addCustomHeader(init)return window
    .fetch(url, init)
    .then(res= > checkStatus(res))
    .then((res) = > res.json())
    .then((res) = > filter(res))
    .catch(err= > console.log('Request failed! + url:${url}`, err));
}

Copy the code

Find a free API to test Baidu has many resources I find here api.uomg.com/doc-rand.im…

Create the API interface file

import fetch from '.. /utils/fetch';

export const getImgList = (sort: string) = > {
  return fetch(`https://api.uomg.com/api/rand.img1?sort=${sort}&format=json`);
};
Copy the code

Use on the page

import { Input, Tag } from 'antd';
import { getImgList } from 'api/test';
import React from 'react';
import { Link } from 'react-router-dom';
import './index.less';

export const Page1 = () = > {
  const [imgurl, setData] = React.useState(' ');
  const [sort, setsort] = React.useState('beauty');

  React.useEffect(() = > {
    getData();
  }, [sort]);

  const getData = () = > {
    getImgList(sort).then((res: { imgurl: string }) = > {
      console.log(res);
      setData(res.imgurl);
    });
  };

  return (
    <div className="test-css">
      <h1 className="test-css-home">I am a Page1</h1>
      <Link to={'/'} >
        <Tag>Return to the home page</Tag>
      </Link>
      <h2>Search images</h2>
      <Input.Search
        style={{ width: 300 }}
        placeholder="Enter keywords such as: beauty, wallpaper, etc."
        onSearch={(value: string) = > setsort(value)}
        enterButton
      />
      <br />
      <img src={imgurl} alt="img" />
    </div>
  );
};
Copy the code

View the complete process and see the project code for yourself

Uploading files (formFetch)

The uploaded files are included in the entire form and submitted together. The file is uploaded using the form

  const handleChange = (e: UploadChangeParam) = > {
    const file = e.fileList[0]? .originFileObj;// File stream object
    const fileName = e.fileList[0].name; / / file name
    const formData = new FormData();
    formData.append('uploadFile', file as any);
    formData.append('fileName', fileName);
    upload(formData).then((res) = > {
      console.log(res);
    });
  };
Copy the code
   export const upload = (obj: FormData) = > {
  return formFetch(`/v3/normal/ecm/package`, {
    method: 'POST'.body: obj,
  });
};
Copy the code

The browser will display it like this

Upload binary data directly

let blob = await new Promise(resolve =>   
  canvasElem.toBlob(resolve,  'image/png')
);

let response = await fetch('/article/fetch/post/image', {
  method:  'POST',
  body: blob
});
Copy the code

reference

# Fetch API tutorial – Untested cancel Fetch request repository: gitee.com/dengruifeng…