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

相关推荐
下雪天的夏风8 分钟前
TS - tsconfig.json 和 tsconfig.node.json 的关系,如何在TS 中使用 JS 不报错
前端·javascript·typescript
diygwcom20 分钟前
electron-updater实现electron全量版本更新
前端·javascript·electron
wn53125 分钟前
【Go - 类型断言】
服务器·开发语言·后端·golang
Hello-Mr.Wang37 分钟前
vue3中开发引导页的方法
开发语言·前端·javascript
希冀1231 小时前
【操作系统】1.2操作系统的发展与分类
后端
程序员凡尘1 小时前
完美解决 Array 方法 (map/filter/reduce) 不按预期工作 的正确解决方法,亲测有效!!!
前端·javascript·vue.js
GoppViper1 小时前
golang学习笔记29——golang 中如何将 GitHub 最新提交的版本设置为 v1.0.0
笔记·git·后端·学习·golang·github·源代码管理
爱上语文2 小时前
Springboot的三层架构
java·开发语言·spring boot·后端·spring
serve the people2 小时前
springboot 单独新建一个文件实时写数据,当文件大于100M时按照日期时间做文件名进行归档
java·spring boot·后端
编程零零七4 小时前
Python数据分析工具(三):pymssql的用法
开发语言·前端·数据库·python·oracle·数据分析·pymssql