javascript高级编程系列 - 使用fetch发送http请求

fetch 采用模块化设计,api分散在多个对象上(Response对象,Request对象,Header对象),
fetch通过数据流(stream对象)处理数据可以分块读取,有利于提高网站性能。

发送GET请求

fetch 函数只传递一个url,默认以get方法发送请求。

  • promise
fetch(url)
.then(response => response.json())
.then(json => console.log(json))
.catch(err => console.log('Request Failed', err)); 
  • async & await
async function getJSON() {
  const url = 'http://example.com';
  try {
    const response = await fetch(url);
    return await response.json();
  } catch (error) {
    console.log('Request Failed', error);
  }
}

发送POST请求

  • 发送表单数据
async function sendPost() {
  const url = 'http://example.com';
  try {
    const response = await fetch(url, {
      method: 'POST',
      headers: {
        "Content-type": "application/x-www-form-urlencoded; charset=UTF-8",
      },
      body: 'foo=bar&lorem=ipsum',
    });
    const json = await response.json();
    console.log(json);
  } catch(error) {
    console.log('Request Failed', error);
  }
}
  • 发送json数据
async function sendJson() {
  const url = 'http://example.com';
  const user =  { name:  'John', surname:  'Smith'  };
  try {
    const response = await fetch(url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json;charset=utf-8'
      }, 
      body: JSON.stringify(user) 
    });
    const json = await response.json();
    console.log(json);
  } catch(error) {
    console.log('Request Failed', error);
  }
}
  • 提交表单数据
const form = document.querySelector('form');
const response = await fetch('/users', {
  method: 'POST',
  body: new FormData(form)
});
  • 文件上传
const input = document.querySelector('input[type="file"]');

const data = new FormData();
data.append('file', input.files[0]);
data.append('user', 'foo');

fetch('/avatars', {
  method: 'POST',
  body: data
});
  • 上传二进制数据
let blob = await new Promise(resolve =>   
  canvasElem.toBlob(resolve,  'image/png')
);

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

判断请求是否成功

  • response.ok
    Response.ok属性返回一个布尔值,表示请求是否成功,true对应 HTTP 请求的状态码 200 到 299,false对应其他的状态码。
async function fetchText() {
  let response = await fetch('/readme.txt');
  if (response.ok) {
    return await response.text();
  } else {
    throw new Error(response.statusText);
  }
}
  • response.status
    Response.status属性返回一个数字,表示 HTTP 回应的状态码(例如200,表示成功请求)。
async function fetchText() {
  let response = await fetch('/readme.txt');
  if (response.status >= 200 && response.status < 300) {
    return await response.text();
  } else {
    throw new Error(response.statusText);
  }
}

读取返回内容的方法

  • response.text():得到文本字符串。
const response = await fetch('/users.html');
const body = await response.text();
document.body.innerHTML = body
  • response.json():得到 JSON 对象。
  • response.blob():得到二进制 Blob 对象。
const response = await fetch('flower.jpg');
const myBlob = await response.blob();
const objectURL = URL.createObjectURL(myBlob);

const myImage = document.querySelector('img');
myImage.src = objectURL;

  • response.formData():得到 FormData 表单对象。
  • response.arrayBuffer():得到二进制 ArrayBuffer 对象。
  • response.clone(): 创建response流对象的副本, 用于多次读取。
  • response.body.getReader(): 返回一个遍历器,这个遍历器的read()方法每次返回一个对象,表示本次读取的内容块。
const response = await fetch('flower.jpg');
const reader = response.body.getReader();

while(true) {

/* 这个对象的done属性是一个布尔值,用来判断有没有读完;value属性是一个 arrayBuffer 数组,表示内容块的内容,
 *  而value.length属性是当前块的大小。
 */
  const {done, value} = await reader.read();

  if (done) {
    break;
  }
  console.log(`Received ${value.length} bytes`)
}

fetch 配置选项

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
});
  1. cache 处理缓存
  • default:默认值,先在缓存里面寻找匹配的请求。
  • no-store:直接请求远程服务器,并且不更新缓存。
  • reload:直接请求远程服务器,并且更新缓存。
  • no-cache:将服务器资源跟本地缓存进行比较,有新的版本才使用服务器资源,否则使用缓存。
  • force-cache:缓存优先,只有不存在缓存的情况下,才请求远程服务器。
  • only-if-cached:只检查缓存,如果缓存里面不存在,将返回504错误。
  1. mode 请求模式
  • cors:默认值,允许跨域请求。
  • same-origin:只允许同源请求。
  • no-cors:请求方法只限于 GET、POST 和 HEAD,并且只能使用有限的几个简单标头,不能添加跨域的复杂标头,相当于提交表单所能发出的请求。
  1. credentials 是否发送cookie
  • same-origin:默认值,同源请求时发送 Cookie,跨域请求时不发送。
  • include:不管同源请求,还是跨域请求,一律发送 Cookie。
  • omit:一律不发送。
  1. keepalive 保持连接
    keepalive属性用于页面卸载时,告诉浏览器在后台保持连接,继续发送数据。

  2. redirect 跳转处理

  • follow:默认值,fetch()跟随 HTTP 跳转。
  • error:如果发生跳转,fetch()就报错。
  • manual:fetch()不跟随 HTTP 跳转,但是response.url属性会指向新的 URL,response.redirected属性会变为true,由开发者自己决定后续如何处理跳转。
  1. referrer
    referrer属性用于设定fetch()请求的referer标头。

  2. referrerPolicy
    referrerPolicy属性用于设定Referer标头的规则。

  • no-referrer-when-downgrade:默认值,总是发送Referer标头,除非从 HTTPS 页面请求 HTTP 资源时不发送。
  • no-referrer:不发送Referer标头。
  • origin:Referer标头只包含域名,不包含完整的路径。
  • origin-when-cross-origin:同源请求Referer标头包含完整的路径,跨域请求只包含域名。
  • same-origin:跨域请求不发送Referer,同源请求发送。
  • strict-origin:Referer标头只包含域名,HTTPS 页面请求 HTTP 资源时不发送Referer标头。
  • strict-origin-when-cross-origin:同源请求时Referer标头包含完整路径,跨域请求时只包含域名,HTTPS 页面请求 HTTP 资源时不发送该标头。
  • unsafe-url:不管什么情况,总是发送Referer标头。
  1. signal 取消请求的实例
    signal属性指定一个 AbortSignal 实例,用于取消fetch()请求
let controller = new AbortController();
setTimeout(() => controller.abort(), 1000);

try {
  let response = await fetch('/long-operation', {
    signal: controller.signal
  });
} catch(err) {
  if (err.name == 'AbortError') {
    console.log('Aborted!');
  } else {
    throw err;
  }
}

参考: https://www.ruanyifeng.com/blog/2020/12/fetch-tutorial.html

posted @ 2024-04-26 16:54  箫笛  阅读(130)  评论(0编辑  收藏  举报