服务端都开始使用 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 运行时和框架中实战。如果这篇文章能帮助到你,不妨点赞、转发来支持作者,感谢。

相关推荐
bcbnb10 小时前
Charles抓包怎么用 Charles抓包工具详细教程、网络调试方法、HTTPS配置与手机抓包实战
后端
Healer91810 小时前
js请求的并发控制
前端
是你的小橘呀10 小时前
从 "渣男" 到 "深情男":Promise 如何让 JS 变得代码变得专一又靠谱
前端·javascript·html
baozj10 小时前
告别截断与卡顿:我的前端PDF导出优化实践
前端·javascript·vue.js
傲文博一10 小时前
为什么我的产品尽量不用「外置」动态链接库
前端·后端
Healer91810 小时前
Promise限制重复请求
前端
梵得儿SHI10 小时前
Vue 响应式原理深度解析:Vue2 vs Vue3 核心差异 + ref/reactive 实战指南
前端·javascript·vue.js·proxy·vue响应式系统原理·ref与reactive·vue响应式实践方案
零日失眠者10 小时前
【系统监控系列】005:CPU温度监控脚本
后端·python
chenyunjie10 小时前
我做了一个编辑国际化i18n json文件的命令行工具
前端
踏浪无痕10 小时前
Maven 依赖拉不下来?一文终结所有坑点
spring boot·后端·面试