@modern-js/main-doc 0.0.0-nightly-20231009160555 → 0.0.0-nightly-20231011160600
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,119 @@
|
|
1
|
+
---
|
2
|
+
sidebar_position: 4
|
3
|
+
title: Custom request SDK
|
4
|
+
---
|
5
|
+
# Custom request SDK
|
6
|
+
|
7
|
+
Modernjs's BFF is isomorphic in CSR and SSR.In the browser side rely on the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch),On the server relies on the [node-fetch](https://www.npmjs.com/package/node-fetch).However, in many business scenarios we need to do some additional processing of the request or response, for example:
|
8
|
+
|
9
|
+
- Write auth information in the request header
|
10
|
+
- Uniform processing of response data or errors
|
11
|
+
- The browser's native fetch function is not available for a particular platform, and other methods of sending requests are required
|
12
|
+
|
13
|
+
For the above scenario, Modern.js provides the `configure` function,the customization capabilities range from low to high and can be used to configure ssr pass-through request headers, interceptors, and request SDKs..
|
14
|
+
|
15
|
+
:::caution
|
16
|
+
The `configure` function call needs to be called before all BFF requests are sent, to ensure that the default request configuration is overridden.
|
17
|
+
|
18
|
+
:::
|
19
|
+
|
20
|
+
|
21
|
+
```ts title="App.tsx"
|
22
|
+
import { configure } from '@modern-js/runtime/bff';
|
23
|
+
|
24
|
+
configure({
|
25
|
+
request: customRequest
|
26
|
+
})
|
27
|
+
```
|
28
|
+
|
29
|
+
## Configure ssr pass-through request headers
|
30
|
+
|
31
|
+
In scenarios where both Modern.js SSR and BFF are used, it is often necessary to pass some request headers on SSR page requests to the BFF service.
|
32
|
+
|
33
|
+
For example, the project has a page address `https://website.com`, which is an SSR page, and the API interface `https://website.com/api/info` will be called in the component, which requires the user's cookie information for authentication. When the page requests this API interface, it needs to pass the `cookie` requested by the SSR page to BFF.
|
34
|
+
|
35
|
+
Currently the following request headers are automatically passed through in Modern.js:
|
36
|
+
|
37
|
+
- cookie
|
38
|
+
- x-tt-logid
|
39
|
+
- user-agent
|
40
|
+
- x-tt-stress
|
41
|
+
|
42
|
+
The request header can be configured via `configure`. For example, in the following example, Modern.js will automatically pass the cookie information of the SSR page request to the BFF service:
|
43
|
+
|
44
|
+
```tsx title="App.tsx"
|
45
|
+
import { configure } from '@modern-js/runtime/bff';
|
46
|
+
|
47
|
+
configure({
|
48
|
+
allowedHeaders: ['x-uid']
|
49
|
+
})
|
50
|
+
```
|
51
|
+
|
52
|
+
## Configuring Interceptors
|
53
|
+
|
54
|
+
In certain business scenarios, there is a requirement for unified processing of requests and responses, and interceptors can be configured to fulfill these requirements in such scenarios.
|
55
|
+
|
56
|
+
```tsx title="App.tsx"
|
57
|
+
configure({
|
58
|
+
// The request here is the default request sdk for bff, and the interceptor function needs to return a new request.
|
59
|
+
// The return value of the new request must be the result of the parse body
|
60
|
+
interceptor(request){
|
61
|
+
return async(url, params) => {
|
62
|
+
const res = await request(url, params);
|
63
|
+
return res.json();
|
64
|
+
};
|
65
|
+
};
|
66
|
+
});
|
67
|
+
```
|
68
|
+
|
69
|
+
## Configure custom request SDK
|
70
|
+
|
71
|
+
If the requirements cannot be met by configuring interceptors alone and need to further customize the request SDK, you can configure the custom request SDK by using the `configure` function:
|
72
|
+
|
73
|
+
:::caution
|
74
|
+
Send a request to the BFF service when the server side renders, Modern.js will find the BFF service intranet IP via **service discovery** and send requests via IP to improve performance. This optimization is **lost** if a custom request SDK is used.
|
75
|
+
|
76
|
+
:::
|
77
|
+
|
78
|
+
```tsx title="App.tsx"
|
79
|
+
import nodeFetch from 'node-fetch';
|
80
|
+
|
81
|
+
const customFetch = (input: RequestInfo | URL, init: RequestInit) => {
|
82
|
+
const curFetch = process.env.MODERN_TARGET !== 'node' ? fetch : nodeFetch as unknown as typeof fetch;
|
83
|
+
return curFetch(input, init).then(async res => {
|
84
|
+
const data = await res.json();
|
85
|
+
data.hello = 'hello custom sdk';
|
86
|
+
return data;
|
87
|
+
});
|
88
|
+
};
|
89
|
+
|
90
|
+
configure({
|
91
|
+
request: customFetch,
|
92
|
+
});
|
93
|
+
```
|
94
|
+
|
95
|
+
The configuration custom request SDK has the following conventions:
|
96
|
+
|
97
|
+
- The `configure` function allows you to configure a `request` function whose input is the same as the Fetch or node-fetch in the browser, and all BFF functions will send requests through this function
|
98
|
+
- The return value of the `request` function must be the actual data returned by the interface, not a Promise, otherwise the BFF function will not return data properly.
|
99
|
+
- In the case of SSR projects, `request` must support both browser-side and server-side sending of requests.
|
100
|
+
|
101
|
+
Example of custom request SDK using axios:
|
102
|
+
|
103
|
+
```tsx title="App.tsx"
|
104
|
+
import { configure } from '@modern-js/runtime/bff';
|
105
|
+
import type { Method, AxiosRequestHeaders as Headers } from 'axios';
|
106
|
+
|
107
|
+
configure({
|
108
|
+
async request(...config: Parameters<typeof fetch>) {
|
109
|
+
const [url, params] = config;
|
110
|
+
const res = await axios({
|
111
|
+
url: url as string, // Here, because of some incompatibility between fetch and axios types, you need to use `as`
|
112
|
+
method: params?.method as Method,
|
113
|
+
data: params?.body,
|
114
|
+
headers: params?.headers as Headers,
|
115
|
+
});
|
116
|
+
return res.data;
|
117
|
+
},
|
118
|
+
});
|
119
|
+
```
|
@@ -0,0 +1,119 @@
|
|
1
|
+
---
|
2
|
+
sidebar_position: 4
|
3
|
+
title: 自定义请求 SDK
|
4
|
+
---
|
5
|
+
# 自定义请求 SDK
|
6
|
+
|
7
|
+
Modern.js 的 BFF 在 CSR 和 SSR 是同构的。在浏览器端依赖了[Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch),在服务端依赖了 [node-fetch](https://www.npmjs.com/package/node-fetch)。但在很多业务场景下我们需要对请求或响应做一些额外的处理,例如:
|
8
|
+
|
9
|
+
- 在请求头中写入鉴权信息
|
10
|
+
- 对响应的数据或错误进行统一的处理
|
11
|
+
- 特定平台无法使用浏览器的原生 fetch 函数,需要使用其他方式发送请求
|
12
|
+
|
13
|
+
针对上述的场景,Modern.js 提供了 `configure` 函数,自定义能力从低到高,可以用它配置 ssr 透传请求头,拦截器,请求 SDK。
|
14
|
+
|
15
|
+
:::caution 注意
|
16
|
+
`configure` 函数的调用需要在所有 BFF 请求发送前调用,以确保覆盖默认的请求配置。
|
17
|
+
|
18
|
+
:::
|
19
|
+
|
20
|
+
|
21
|
+
```ts title="App.tsx"
|
22
|
+
import { configure } from '@modern-js/runtime/bff';
|
23
|
+
|
24
|
+
configure({
|
25
|
+
request: customRequest
|
26
|
+
})
|
27
|
+
```
|
28
|
+
|
29
|
+
## 配置 ssr 透传请求头
|
30
|
+
|
31
|
+
在同时使用 Modernjs SSR 和 BFF 的场景下,常常需要将 SSR 页面请求上的一些请求头信息,透传给 BFF 服务。
|
32
|
+
|
33
|
+
例如项目有页面地址是 `https://website.com`,该页面是 SSR 的,在组件中会调用 API 接口 `https://website.com/api/info`,该接口需要用户的 cookie 信息做鉴权。页面在请求该 API 接口时,需要将 SSR 页面请求的 `cookie` 传给 BFF。
|
34
|
+
|
35
|
+
目前以下请求头在 Modernjs 中是自动透传的:
|
36
|
+
|
37
|
+
- cookie
|
38
|
+
- x-tt-logid
|
39
|
+
- user-agent
|
40
|
+
- x-tt-stress
|
41
|
+
|
42
|
+
可以通过 `configure` 配置请求头。例如以下例子,Modern.js 会自动将 SSR 页面请求的 cookie 信息透传给 BFF 服务:
|
43
|
+
|
44
|
+
```tsx title="App.tsx"
|
45
|
+
import { configure } from '@modern-js/runtime/bff';
|
46
|
+
|
47
|
+
configure({
|
48
|
+
allowedHeaders: ['x-uid']
|
49
|
+
})
|
50
|
+
```
|
51
|
+
|
52
|
+
## 配置拦截器
|
53
|
+
|
54
|
+
在有些业务场景下需要对请求和响应进行一些统一的处理,这种场景下可以配置拦截器满足需求:
|
55
|
+
|
56
|
+
```tsx title="App.tsx"
|
57
|
+
configure({
|
58
|
+
// 这里的 request 是一体化默认的请求工具,interceptor 函数需返回一个新的 request。
|
59
|
+
// 新 request 的出参必须是 parse body 之后的结果
|
60
|
+
interceptor(request){
|
61
|
+
return async(url, params) => {
|
62
|
+
const res = await request(url, params);
|
63
|
+
return res.json();
|
64
|
+
};
|
65
|
+
}
|
66
|
+
});
|
67
|
+
```
|
68
|
+
|
69
|
+
## 配置自定义请求 SDK
|
70
|
+
|
71
|
+
如果仅仅通过配置拦截器无法满足需求,需要对请求的 SDK 做进一步的自定义,可以通过 `configure` 函数配置自定义请求 SDK:
|
72
|
+
|
73
|
+
:::caution 注意
|
74
|
+
在 SSR 和一体化调用的场景下,在 SSR 向 BFF 服务发送请求时,Modern.js 会通过**服务发现**找到 BFF 服务内网 IP,并通过 IP 发送请求,以提高性能。如果使用自定义请求 SDK 会**失去这种优化**。
|
75
|
+
|
76
|
+
:::
|
77
|
+
|
78
|
+
```tsx title="App.tsx"
|
79
|
+
import nodeFetch from 'node-fetch';
|
80
|
+
|
81
|
+
const customFetch = (input: RequestInfo | URL, init: RequestInit) => {
|
82
|
+
const curFetch = process.env.MODERN_TARGET !== 'node' ? fetch : nodeFetch as unknown as typeof fetch;
|
83
|
+
return curFetch(input, init).then(async res => {
|
84
|
+
const data = await res.json();
|
85
|
+
data.hello = 'hello custom sdk';
|
86
|
+
return data;
|
87
|
+
});
|
88
|
+
};
|
89
|
+
|
90
|
+
configure({
|
91
|
+
request: customFetch,
|
92
|
+
});
|
93
|
+
```
|
94
|
+
|
95
|
+
配置自定义请求 SDK 有以下约定:
|
96
|
+
|
97
|
+
- 通过 `configure` 函数可以配置一个 `request` 函数,这个函数的入参与浏览器中的 Fetch 或 node-fetch 对齐,所有的一体化 BFF 函数会通过该函数发送请求。
|
98
|
+
- `request` 函数出参必须是接口实际返回的数据,不能是 Promise,否则会导致一体化 BFF 函数无法正常返回数据。
|
99
|
+
- 如果是 SSR 项目,`request` 必须要同时支持浏览器端和服务器端发送请求。
|
100
|
+
|
101
|
+
使用 axios 定制自定义请求 SDK 的示例:
|
102
|
+
|
103
|
+
```tsx title="App.tsx"
|
104
|
+
import { configure } from '@modern-js/runtime/bff';
|
105
|
+
import type { Method, AxiosRequestHeaders as Headers } from 'axios';
|
106
|
+
|
107
|
+
configure({
|
108
|
+
async request(...config: Parameters<typeof fetch>) {
|
109
|
+
const [url, params] = config;
|
110
|
+
const res = await axios({
|
111
|
+
url: url as string, // 这里因为 fetch 和 axios 类型有些不兼容,需要使用 as
|
112
|
+
method: params?.method as Method,
|
113
|
+
data: params?.body,
|
114
|
+
headers: params?.headers as Headers,
|
115
|
+
});
|
116
|
+
return res.data;
|
117
|
+
},
|
118
|
+
});
|
119
|
+
```
|
package/package.json
CHANGED
@@ -15,17 +15,17 @@
|
|
15
15
|
"modern",
|
16
16
|
"modern.js"
|
17
17
|
],
|
18
|
-
"version": "0.0.0-nightly-
|
18
|
+
"version": "0.0.0-nightly-20231011160600",
|
19
19
|
"publishConfig": {
|
20
20
|
"registry": "https://registry.npmjs.org/",
|
21
21
|
"access": "public",
|
22
22
|
"provenance": true
|
23
23
|
},
|
24
24
|
"dependencies": {
|
25
|
-
"@modern-js/sandpack-react": "0.0.0-nightly-
|
25
|
+
"@modern-js/sandpack-react": "0.0.0-nightly-20231011160600"
|
26
26
|
},
|
27
27
|
"peerDependencies": {
|
28
|
-
"@modern-js/builder-doc": "0.0.0-nightly-
|
28
|
+
"@modern-js/builder-doc": "0.0.0-nightly-20231011160600"
|
29
29
|
},
|
30
30
|
"devDependencies": {
|
31
31
|
"classnames": "^2",
|
@@ -35,12 +35,12 @@
|
|
35
35
|
"ts-node": "^10.9.1",
|
36
36
|
"typescript": "^5",
|
37
37
|
"fs-extra": "^10",
|
38
|
-
"rspress": "1.0.0-beta.
|
39
|
-
"@rspress/shared": "1.0.0-beta.
|
38
|
+
"rspress": "1.0.0-beta.3",
|
39
|
+
"@rspress/shared": "1.0.0-beta.3",
|
40
40
|
"@types/node": "^16",
|
41
41
|
"@types/fs-extra": "^9",
|
42
|
-
"@modern-js/builder-doc": "0.0.0-nightly-
|
43
|
-
"@modern-js/doc-plugin-auto-sidebar": "0.0.0-nightly-
|
42
|
+
"@modern-js/builder-doc": "0.0.0-nightly-20231011160600",
|
43
|
+
"@modern-js/doc-plugin-auto-sidebar": "0.0.0-nightly-20231011160600"
|
44
44
|
},
|
45
45
|
"scripts": {
|
46
46
|
"dev": "rspress dev",
|