Design and Implementation of a Unified Front-End Request Library Based on Middleware Pattern
Bilibili created a unified front‑end request library using a Koa‑style middleware “onion” architecture—ConfigCtrl, AssembleCtrl, and RequestCtrl—to standardize error handling, cut code redundancy, improve performance, and provide consistent, extensible API calls across SSR/CSR, Vue2/Vue3, and in‑app H5 environments.
Front‑end engineers frequently need to call back‑end APIs, and there are many existing approaches such as XHR, Axios and fetch. To address the fragmentation and inefficiencies of these solutions, Bilibili designed a unified request library that provides standardized error handling, reduces code redundancy, smooths style differences, lowers documentation overhead and improves IDE assistance.
The main pain points that motivated the library are:
Code redundancy and high maintenance cost caused by multiple versions of request utilities (SSR/CSR, Vue2/Vue3, in‑app H5, etc.).
Performance issues due to bloated libraries.
Lack of coordinated evolution between front‑end and back‑end, leading to duplicated implementations for the same back‑end capability.
After researching community solutions (Axios, native fetch, etc.) the team concluded that a middleware‑based design offers the most flexibility. The library adopts the “onion” model inspired by Koa, where each middleware handles a specific concern (logging, error handling, data conversion, etc.) and the request/response passes through the chain forward and backward.
Architecture
The system is organized around three controllers:
ConfigCtrl : creates the middleware context and stores configuration for each request.
AssembleCtrl : assembles global and temporary middlewares together with a payload, allowing addition, removal or disabling of middlewares.
RequestCtrl : builds the final request function, combines it with the context, and executes the HTTP call.
Middleware are defined by an abstract base class, enabling type checking and consistent interfaces. Global middlewares are registered at instantiation, while temporary middlewares can be attached per request via the with API. The library also distinguishes Fetch‑specific middleware from others, placing the Fetch middleware at the core of the onion.
Example of the core type definitions:
export interface IHttpServiceInit {
baseURL?: FetchBaseURL;
fetch?: IHttpSvcMiddleware;
middlewares?: IHttpSvcMiddleware[];
}
class HttpService {
constructor(initConfig?: IHttpServiceInit | IHttpSvcMiddleware[]);
// ... other methods
}Example of registering a global middleware and using the chainable API:
const globalMeta = (ctx, next, config) => {
if (config?.payload?.active) {
ctx.request.params["meta"] = {
platform: "web",
device: ""
};
}
await next();
};
class GlobalMeta extends Middleware {
name = "GLOBA_META";
constructor() { super(globalMeta); }
}
const httpSvc = new HttpService([new GlobalMeta()]);
// Register but not active by default
httpSvc.with("GLOBAL_META", { active: true });
httpSvc
.with(encodeHandler)
.with(reportHandler)
.with('RES_DATA', { type: 'text' })
.disable('RES_EXTRACT')
.with('SERVER_SIDE', { headers: context.headers || {} })
.request({ url: '/xxx', params: { id: 1 } });The library also separates middleware into its own npm package, reducing the learning curve for users and allowing independent versioning.
Visual illustrations (omitted here) show the onion model, the controller interaction diagram, and the overall design flow.
Benefits of adopting the unified request library include a single entry point for company‑wide capabilities, reduced development effort, consistent behavior across platforms (web, native H5, etc.), and a solid foundation for a sustainable front‑end ecosystem.
For more details, examples and community‑contributed middlewares, refer to the project’s GitHub repository: https://github.com/bilibili/http-service .
Bilibili Tech
Provides introductions and tutorials on Bilibili-related technologies.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.