Docs

Documentation versions (currently viewingVaadin 24)
Documentation translations (currently viewingChinese)

此页面是对官方文档(http://vaadin.com/docs)进行的机器翻译。它可能存在错误、不准确或误述。Vaadin 不保证翻译的准确性、可靠性或及时性,也不对其做任何声明。

客户端中间件

在 Hilla 中,中间件会拦截每一次调用的请求和响应,从而能够处理请求及其响应。

Hilla 中的中间件是一种特殊的 TypeScript 异步回调函数,在前端调用后端时执行。 它截获每次调用的请求和响应。 中间件可以获取调用上下文信息,包括端点(endpoint)和方法的名称,提供的参数及其他客户端调用选项。

客户端中间件属于高级主题,不建议大部分用户使用。

适用场景

中间件可用于处理请求及其响应。 典型的用例如下:

  • 性能测量

  • 请求日志记录

  • 重试机制

  • 批处理请求

  • 响应缓存

  • 自定义请求和响应的头部与主体处理

中间件结构

以下是一个用于日志记录的中间件示例及其结构解析。

Source code
my-log-middleware.ts
import { Middleware, MiddlewareContext, MiddlewareNext } from '@vaadin/hilla-frontend';

// 中间件就是一个异步函数,接收 `context` 和 `next` 参数
export const MyLogMiddleware: Middleware = async function(
  context: MiddlewareContext,
  next: MiddlewareNext
) {
  // context 对象包含调用参数,详细描述见 ConnectClient 类的 `call` 方法
  const {endpoint, method, params} = context;
  console.log(
    `Sending request to endpoint: ${endpoint} ` +
    `method: ${method} ` +
    `parameters: ${JSON.stringify(params)} `
  );

  // 另外,context 包含一个将通过网络发送的 Fetch API `Request` 实例。
  const request: Request = context.request;
  console.log(`${request.method} ${request.url}`);

  // 调用下一个(next)异步函数,发送请求并获取响应。
  const response: Response = await next(context);

  // 响应为 Fetch API 的 `Response` 对象。
  console.log(`Received response: ${response.status} ${response.statusText}`);

  // 如果需要读取响应正文,可以克隆响应对象
  const responseClone = response.clone();
  console.log(await responseClone.text());

  // 中间件返回一个响应。
  return response;
}
Note
RequestResponse 是 Fetch API 接口。

Hilla 中间件并未创建新的数据结构以表示网络请求与响应,而是使用由 Fetch API specification 声明的接口。

请访问 MDN web 文档以了解更多关于 Request APIResponse API的信息。

在客户端中使用中间件

如需使用中间件,在实例化 Hilla TypeScript 客户端时,将您自定义的中间件放入 middlewares 数组选项:

Source code
connect-client.ts
import { ConnectClient } from '@vaadin/hilla-frontend';
import { MyLogMiddleware } from './my-log-middleware';

const client = new ConnectClient({
  prefix: '/connect',
  middlewares: [MyLogMiddleware]
});

export default client;

或者,您也可以在已有客户端(例如生成的客户端)上修改 middlewares 数组:

Source code
index.ts
import client from 'Frontend/generated/connect-client.default';
import { MyLogMiddleware } from './my-log-middleware';

client.middlewares = [MyLogMiddleware];
Caution
在运行时修改中间件
如果修改了 middlewares 数组,只有在修改后发起的请求才会使用新的 middlewares 数组。 为避免因此导致的问题,建议避免修改 middlewares,或只在首次调用前修改 middlewares

使用中间件修改请求

如需在中间件内部对请求进行低级别修改,可将 context.request 替换为新的 Fetch API Request 实例:

Source code
my-api-dispatcher-middleware.ts
import { Middleware, MiddlewareContext, MiddlewareNext } from '@vaadin/hilla-frontend';

// 一个示例中间件,针对特定请求使用另一台服务器
export const MyApiDispatcherMiddleware: Middleware = async function(
  context: MiddlewareContext,
  next: MiddlewareNext
) {
  if (context.endpoint === 'ExternalEndpoint') {
    const url = context.request.url.replace(
      'http//my-app.example.com',
      'http://external-endpoint.example.com'
    );
    context.request = new Request(url, context.request);
  }

  return await next(context);
};

使用中间件自定义响应

中间件也可以通过返回一个自定义的 Response 实例替换实际响应:

Source code
my-stub-middleware.ts
import { Middleware, MiddlewareContext, MiddlewareNext } from '@vaadin/hilla-frontend';

// 一个示例中间件,针对特定端点返回空响应,而不是调用后端端点
export const MyStubMiddleware: Middleware = async function(
  context: MiddlewareContext,
  next: MiddlewareNext
) {
  if (context.endpoint === 'StubEndpoint') {
    //
    return new Response('{}');
  }

  return await next(context);
}