Skip to content

Commit 2ba69a8

Browse files
committed
docs(chinese): translate middleware-auth
1 parent 02fbe58 commit 2ba69a8

File tree

2 files changed

+160
-5
lines changed

2 files changed

+160
-5
lines changed

docs/.vitepress/zh.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export const zh = defineConfig({
3131
items: [
3232
{ text: "快速上手", link: "/zh/openapi-fetch/" },
3333
{
34-
text: "中间件与认证方式",
34+
text: "中间件 & 身份认证",
3535
link: "/zh/openapi-fetch/middleware-auth",
3636
},
3737
{ text: "测试", link: "/zh/openapi-fetch/testing" },
Lines changed: 159 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,166 @@
11
---
2-
title: Middleware & Auth
2+
title: 中间件 & 身份认证
33
---
44

5-
# Middleware & Auth
5+
# 中间件 & 身份认证
66

7-
::: warning
7+
中间件允许您修改所有获取的请求、响应或两者之间的内容。其中一个最常见的用例是身份验证,但也可以用于日志记录/性能监控、抛出错误或处理特定的边缘情况。
88

9-
This article is a stub. Please help [expand it](https://github.com/drwpow/openapi-typescript/tree/main/docs/zh/)!
9+
## 中间件
10+
11+
每个中间件都可以提供 `onRequest()``onResponse()` 回调,用于观察/变更请求和响应。
12+
13+
```ts
14+
import createClient from "openapi-fetch";
15+
import type { paths } from "./api/v1";
16+
17+
const myMiddleware: Middleware = {
18+
async onRequest(req, options) {
19+
// 设置 "foo" 标头
20+
req.headers.set("foo", "bar");
21+
return req;
22+
},
23+
async onResponse(res, options) {
24+
const { body, ...resOptions } = res;
25+
// 更改响应的状态
26+
return new Response(body, { ...resOptions, status: 200 });
27+
},
28+
};
29+
30+
const client = createClient<paths>({ baseUrl: "https://myapi.dev/v1/" });
31+
32+
// 注册中间件
33+
client.use(myMiddleware);
34+
```
35+
36+
::: tip
37+
38+
中间件注册的顺序很重要。对于请求,`onRequest()` 将按注册的顺序调用。对于响应,`onResponse()` 将以**反向**顺序调用。这样,第一个中间件获取第一个请求的“权利”,并对最终响应具有最终控制权。
1039

1140
:::
41+
42+
### 跳过
43+
44+
如果您想在某些条件下跳过中间件,只需尽早`return`
45+
46+
```ts
47+
onRequest(req) {
48+
if (req.schemaPath !== "/projects/{project_id}") {
49+
return undefined;
50+
}
51+
//
52+
}
53+
```
54+
55+
这将使请求/响应保持不变,并将事务传递给下一个中间件处理程序(如果有的话)。不需要内部回调或观察者库。
56+
57+
### 抛出
58+
59+
中间件还可以用于抛出 `fetch()` 通常不会抛出的错误,在像 [TanStack Query](https://tanstack.com/query/latest) 这样的库中很有用:
60+
61+
```ts
62+
onResponse(res) {
63+
if (res.error) {
64+
throw new Error(res.error.message);
65+
}
66+
}
67+
```
68+
69+
### 移除中间件
70+
71+
要移除中间件,请调用 `client.eject(middleware)`
72+
73+
```ts{9}
74+
const myMiddleware = {
75+
// …
76+
};
77+
78+
// 注册中间件
79+
client.use(myMiddleware);
80+
81+
// 移除中间件
82+
client.eject(myMiddleware);
83+
```
84+
85+
### 处理状态性
86+
87+
由于中间件使用本机 `Request``Response` 实例,重要的是要记住 [bodies are stateful](https://developer.mozilla.org/en-US/docs/Web/API/Response/bodyUsed)。这意味着:
88+
89+
- 当进行修改时**创建新实例**`new Request()` / `new Response()`
90+
-**不修改****克隆**`res.clone().json()`
91+
92+
默认情况下,`openapi-fetch` **不会**为了性能而任意克隆请求/响应;由您负责创建干净的副本。
93+
94+
<!-- prettier-ignore -->
95+
96+
```ts
97+
const myMiddleware: Middleware = {
98+
onResponse(res) {
99+
if (res) {
100+
const data = await res.json(); // [!code --]
101+
const data = await res.clone().json(); // [!code ++]
102+
return undefined;
103+
}
104+
},
105+
};
106+
```
107+
108+
## 身份验证
109+
110+
这个库是非常开放的,并且可以与任何 [Authorization](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization) 设置一起使用。但是这里有一些建议,可能会身份验证更容易。
111+
112+
### 基本身份验证
113+
114+
这个基本示例使用中间件在每个请求时检索最新的令牌。在我们的示例中,访问令牌保存在JavaScript模块状态中,这对于客户端应用程序是安全的,但对于服务器应用程序应该避免。
115+
116+
```ts
117+
import createClient, { type Middleware } from "openapi-fetch";
118+
import type { paths } from "./api/v1";
119+
120+
let accessToken: string | undefined = undefined;
121+
122+
const authMiddleware: Middleware = {
123+
async onRequest(req) {
124+
// 获取令牌,如果不存在
125+
if (!accessToken) {
126+
const authRes = await someAuthFunc();
127+
if (authRes.accessToken) {
128+
accessToken = authRes.accessToken;
129+
} else {
130+
// 处理身份验证错误
131+
}
132+
}
133+
134+
// (可选) 在此添加逻辑以在令牌过期时刷新令牌
135+
136+
// 在每个请求中添加 Authorization 标头
137+
req.headers.set("Authorization", `Bearer ${accessToken}`);
138+
return req;
139+
},
140+
};
141+
142+
const client = createClient<paths>({ baseUrl: "https://myapi.dev/v1/" });
143+
client.use(authMiddleware);
144+
145+
const authRequest = await client.GET("/some/auth/url");
146+
```
147+
148+
### 条件身份认证
149+
150+
如果某些路由不需要授权,您也可以使用中间件处理:
151+
152+
```ts
153+
const UNPROTECTED_ROUTES = ["/v1/login", "/v1/logout", "/v1/public/"];
154+
155+
const authMiddleware = {
156+
onRequest(req) {
157+
if (UNPROTECTED_ROUTES.some((pathname) => req.url.startsWith(pathname))) {
158+
return undefined; // 不要修改某些路径的请求
159+
}
160+
161+
// 对于所有其他路径,按预期设置 Authorization 标头
162+
req.headers.set("Authorization", `Bearer ${accessToken}`);
163+
return req;
164+
},
165+
};
166+
```

0 commit comments

Comments
 (0)