服务端都开始使用 Fetch Web API了,还不熟悉的看这里!

一、开始之前

Bun 最近发布带来最新的 v1 正式版,Bun 大而全的设计,并且贴近 Web API 标准,这里 Bun 目前支持了这些 Web API 标准,其中就包含了 fetch API, 并且 Node.js 在 Node.js v17.5.0 中实验性的增加了 fetch

二、Node.js 中的 Fetch

2.1)使用实验性 --experimental-fetch

ts 复制代码
async function getData() {
    const response = await fetch('https://github.com/');
    const body = await response.text();
    console.log(body);
}

getData()
sh 复制代码
node app.js --experimental-fetch

Node.js 的 fetch 目前还处于试验阶段,但是社区已经实现了响应的功能。

2.2)使用社区实现 node-fetch

ts 复制代码
import fetch from 'node-fetch';

const response = await fetch('https://github.com/');
const body = await response.text();

console.log(body);

三、其他服务端直接支持 Fetch API 的框架

服务支持 Fetch API 后,可方便的使用 fetch 函数,同时响应数据的方式也带来了影响,之间使用 Node HTTP repsonse.end 方法进行响应,显然直接使用 fetch apis 中的 Response 构造函数进行响应。

3.1)Bun 运行时

ts 复制代码
Bun.serve({
  fetch(req) {
    return new Response("Bun!");
  },
});

bun 对 fetch API 的支持最为直接 serve 的参数名就是 fetch, fetch 函数就是 request, 响应数据的时候使用 fetch API Response 即可。

3.2) Deno 运行时

ts 复制代码
import { serve } from "https://deno.land/std@0.140.0/http/server.ts";

async function handler(req: Request): Promise<Response> {
  const resp = await fetch("https://api.github.com/users/denoland", {
    headers: {
      accept: "application/json",
    },
  });
  return new Response(resp.body, {
    status: resp.status,
    headers: {
      "content-type": "application/json",
    },
  });
}

serve(handler);

Deno 与 Bun 类似在 serve 服务中接收 request 对象,然后响应 Response 实例,

3.3)Remix loader/action

ts 复制代码
export async function loader() {
  const users = await db.users.findMany();
  const body = JSON.stringify(users);
  return new Response(body, {
    headers: {
      "Content-Type": "application/json",
    },
  });
}

四、Web 标准 Fetch API 深度解读

4.1)fetch 相关 API设计:分块设计

api 说明
fetch 核心请求函数,主打 promise 风格
Request 请求对象构造函数
Response 响应对象构造函数
Headers 请求头构造函数

4.2)与 fetch 相关的 api

api 说明
AbortController 取消控制器
FormData 表单
URLSearchParams 参数

4.3) fetch 函数的用法

4.3.1)用法一、单独传递字符串

ts 复制代码
fetch(url)

4.3.2)用法二、传递第二个参数

以对象的形式配置: 请求方式请求头请求体 等等,其中请求支持:

body 类型 说明
字符串 默认即可
json字符串 'Content-Type': 'application/json;charset=utf-8' 头进行配合使用
表单 使用FormData 对象 配合 application/x-www-form-urlencoded
文件上传 使用表单提交,自动配置
二进制 Blob 或 arrayBuffer 格式上传
css 复制代码
fetch(url, {
      method: 'POST',
      headers: {
        "Content-type": "application/x-www-form-urlencoded; charset=UTF-8",
      },
      body: 'foo=bar&lorem=ipsum',
})
属性名 描述
method HTTP 请求方法(例如,'GET'、'POST')
headers 包含请求头信息的对象,用于自定义请求头
body 请求主体数据,可以是文本、二进制数据、表单数据等
mode 请求模式,例如 'cors'、'no-cors'、'same-origin'
cache 缓存模式,例如 'default'、'no-store'、'reload'
credentials 请求凭证模式,例如 'same-origin'、'include'、'omit'
redirect 重定向模式,例如 'follow'、'error'、'manual'
referrer 请求的引用页
integrity 用于验证资源完整性的哈希值
keepalive 是否启用 keep-alive 功能
signal 用于取消请求的信号对象,可用于中止请求

4.3.3)用法三、使用 Request 构造器与 fetch 函数

ts 复制代码
// 创建一个简单的 GET 请求
const getRequest = new Request('your_request_url', {
  method: 'GET',
  headers: new Headers({
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
  }),
});


// 使用 Request 对象发送请求
fetch(getRequest)
  .then(response => {
    // 处理 GET 请求的响应
  })
  .catch(error => {
    // 处理 GET 请求的错误
  });

五、示例

5.1) bun 服务端 fetch + 浏览器 fetch

sh 复制代码
bun create vite my-app
  • bun 服务端
ts 复制代码
import { serve } from 'bun';

serve({
  port: 3000,
  async fetch(req) {
    if (req.method === 'POST') {
      const bodyStream = req.body
      const _body = await Bun.readableStreamToJSON(bodyStream);
      const __body = {..._body, a: _body.a + 2}
      // 处理 POST 请求
      const body = 'Hello, POST request!' + JSON.stringify(__body);
      const headers = {'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST'}
      return new Response(body, { headers });
    } else {
      // 处理其他类型的请求
      const body = 'Hello, GET request!';
      const headers = { 'Content-Type': 'text/plain' };
      return new Response(body, { headers });
    }
  }
});

注意: 配置跨域配置, bun 中 post 请求的请求体通过 Bun.readableStreamToJSON(bodyStream) 获取。

  • react 客户端
ts 复制代码
import { useEffect, useState } from 'react'


function App() {
  const [data, setData] = useState()

  const postData = async () => {
    fetch('http://localhost:3000', {
      method: 'POST',
      mode: 'cors',
      body: JSON.stringify({ a: 1, b: 2 })
    }).then((response) => {
      return response.json()
    }).then((data) => {
      setData(data)
    })
  }

  useEffect(() => {
    postData()
  }, [])
  return (
    <>
      // ...
    </>
  )
}

export default App

使用浏览器的快鱼的时候,配置 mode: 'cors'属性。提示:也可以通过 vite 的代理配置跨域。

5.2) Remix 中使用 fetch

使用 bun 创建项目

sh 复制代码
bun create remix fetch
tsx 复制代码
import type { ActionArgs, V2_MetaFunction } from "@remix-run/node";
import { Form } from '@remix-run/react'

export async function action({ request }: ActionArgs) {
  const body = await request.formData(); // 获取表单数据
  const title = body.get('title')
  const description = body.get('description')

  return new Response(JSON.stringify({title, description})) // fetch Response 相应
}

export const meta: V2_MetaFunction = () => {
  return [
    { title: "New Remix App" },
    { name: "description", content: "Welcome to Remix!" },
  ];
};

export default function Index() {
  return (
    <div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.8" }}>
      <h1>Welcome to Remix</h1>
      <Form method="post">
        <input type="text" name="title" />
        <input type="text" name="description" />
        <button type="submit">提交</button> // 默认发送 fetch 请求
      </Form>
    </div>
  );
}

Remix 中表单提交并自动发送 fetch 请求,因为前后端统一,所以不存在跨域的情况。在 Remix action 函数中获取表单提交的数据,最后使用 fetch api 中的 Response 将请求过来的数据 stringify 化,响应给表单的提交接口,可以使用 useActionData 来获取,这里就不再说明。

小结

本文核心是讲解 服务端的运行时 fetch 支持与使用情况,社区都在朝着 Web API 靠近,Deno/Bun/remix... Fetch API 虽然在前端有使用,但使用规模并不大,随着服务端靠近 Web API,使用会更加频繁,所以一个开发者对 Web API 标准掌握要更加的熟练。本文总结了 Fetch 相关的 API侧重于服务端的使用,并在不同的 JS 运行时和框架中实战。如果这篇文章能帮助到你,不妨点赞、转发来支持作者,感谢。

相关推荐
Estar.Lee2 小时前
查手机号归属地免费API接口教程
android·网络·后端·网络协议·tcp/ip·oneapi
y先森3 小时前
CSS3中的伸缩盒模型(弹性盒子、弹性布局)之伸缩容器、伸缩项目、主轴方向、主轴换行方式、复合属性flex-flow
前端·css·css3
前端Hardy3 小时前
纯HTML&CSS实现3D旋转地球
前端·javascript·css·3d·html
susu10830189113 小时前
vue3中父div设置display flex,2个子div重叠
前端·javascript·vue.js
IT女孩儿4 小时前
CSS查缺补漏(补充上一条)
前端·css
2401_857610034 小时前
SpringBoot社团管理:安全与维护
spring boot·后端·安全
凌冰_4 小时前
IDEA2023 SpringBoot整合MyBatis(三)
spring boot·后端·mybatis
码农飞飞5 小时前
深入理解Rust的模式匹配
开发语言·后端·rust·模式匹配·解构·结构体和枚举
一个小坑货5 小时前
Rust 的简介
开发语言·后端·rust
吃杠碰小鸡5 小时前
commitlint校验git提交信息
前端