Skip to content

fetch

https://caniuse.com/?search=fetch

https://developer.mozilla.org/zh-CN/docs/Web/API/fetch

js
const promise = fetch(url, [options]);

Http 可以简单的分为两个阶段

  1. 获取 response header
  2. 获取 response body

fetch 的 response body 需要自己处理,如 .text() .json() .formData() .blob() .arrayBuffer()

fetch 的 response body 只能处理一次。

get

直接请求就是 GET

post

如下

js
const body = JSON.stringify({ hello: "world" });

let response = await fetch(url, {
  method: "POST",
  headers: {
    "Content-Type": "application/json;charset=utf-8",
  },
  body,
});

请求头:

js
fetch(url, {
  headers: {
    Authentication: "secret",
  },
});

响应头

js
const response = await fetch(
  "https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits"
);

response.headers.get("Content-Type"); // application/json; charset=utf-8

响应头是一个类似 Map 的可迭代

js
for (let [key, value] of response.headers) {
  //
}

from data

如例:

js
let imageBlob = await new Promise((resolve) =>
  canvasElem.toBlob(resolve, "image/png")
);

let formData = new FormData();
formData.append("firstName", "John");
formData.append("image", imageBlob, "image.png");

let response = await fetch("/article/formdata/post/image-form", {
  method: "POST",
  body: formData,
});

from data 提供如下 api:

  • formData.append(name, value) —— 添加表单字段,
  • formData.append(name, blob, fileName) —— 添加一个 blob 字段。就像它是 <input type="file">。fileName 设置文件名而不是表单字段名。
  • formData.delete(name) —— 删除
  • formData.get(name) —— 获取
  • formData.has(name) —— 是否存在。

abort

AbortController 可以关联多个 fetch,也就可以一口气请求多个。

js
let controller = new AbortController();

fetch(url, {
  signal: controller.signal,
});

// 取消
controller.abort();

单纯的取消 promise

js
let controller = new AbortController();

new Promise((resolve, reject) => {
  // ... do something ...
  controller.signal.addEventListener("abort", reject);
});

config more

https://zh.javascript.info/fetch-api

referrerreferrerPolicy:HTTP 的 Referer header

mode cors | same-origin | no-cors 允许跨源请求|禁止跨源请求|只允许安全请求

credentials same-origin | include | omit
跨源不发送|总是发送|不发送
fetch 是否应该随请求发送 cookie 和 HTTP-Authorization header

cache default | no-store | reload | no-cache | force-cache | only-if-cached

redirect follow | error | manual
遵循 HTTP 重定向 | HTTP 重定向时报错 | 允许手动处理 HTTP 重定向

integrity hash 支持具体看浏览器,一般有 SHA-256,SHA-384,和 SHA-512

js
// 下载一个文件,使用 SHA-256 校验和为 “abcdef”
fetch("http://site.com/file", {
  integrity: "sha256-abcdef",
});

keepalive 请求在网页关闭后继续存在

一个简单的 fetch 封装

js
interface IGetPrams {
  [key: string]: string | number | boolean;
}

/**
 * URL 处理
 */
export const createURL = (
  url: string,
  config?: { param?: IGetPrams, base?: string }
) => {
  const u = new URL(url, config?.base);

  const param = config?.param;

  if (param) {
    for (const key of Object.keys(param)) {
      const value = param[key];
      u.searchParams.set(key, value + "");
    }
  }

  return u;
};

type IHttpConfig = RequestInit & {};

/**
 * post 请求
 *
 * 使用 response.json() 处理
 */
export const post = async (
  url: string | URL,
  data?: any,
  config?: IHttpConfig
) => {
  const u = typeof url === "string" ? createURL(url, { base: baseURL }) : url;

  const headers = {
    "Content-Type": "application/json;charset=utf-8",
  };

  if (config) {
    const { headers: h } = config;
    if (h) Object.assign(headers, h);
  }

  const response = await fetch(u, {
    ...config,
    method: "POST",
    headers,
    body: JSON.stringify(data),
  });

  return response.json();
};

/**
 * get 请求
 *
 * 使用 response.json() 处理
 */
export const get = async (
  url: string | URL,
  data?: IGetPrams,
  config?: IHttpConfig
) => {
  const u =
    typeof url === "string"
      ? createURL(url, { base: baseURL, param: data })
      : url;

  const response = await fetch(u, {
    ...config,
  });

  return response.json();
};

export const setBaseURL = (url: string) => {
  baseURL = url;
};

export const getBaseURL = () => baseURL;
let baseURL = "";