# Integration Architecture of the EXTERNAL_API_SERVICE in wechat-article-exporter

> Explore the EXTERNAL_API_SERVICE integration architecture, a Nitro gateway securely proxying WeChat MP requests and managing public proxies for efficient server-side access.

- Repository: [公众号文章工具箱/wechat-article-exporter](https://github.com/wechat-article/wechat-article-exporter)
- Tags: architecture
- Published: 2026-05-26

---

**The External API Service acts as a secure Nitro-based gateway that proxies WeChat MP requests through cookie-aware handlers, optionally routing traffic via a managed pool of public proxies while keeping direct WeChat access server-side.**

The `wechat-article/wechat-article-exporter` repository implements an **External API Service** architecture that exposes public HTTP endpoints under `server/api/public/v1/` while shielding clients from direct WeChat MP interaction. This Nuxt 3 server-side layer handles authentication cookie persistence, request header spoofing, and intelligent proxy failover to ensure reliable data extraction from WeChat's official APIs.

## Core Request Flow Architecture

The External API Service operates as a thin reverse proxy that normalizes client requests into browser-authenticated WeChat MP calls. The architecture follows a strict five-phase pipeline:

1. **Client Request** – External clients call public endpoints like `GET /api/public/v1/article` with query parameters.
2. **Token Retrieval** – The handler invokes `getTokenFromStore(event)` to retrieve WeChat authentication cookies from the KV-backed **CookieStore**.
3. **Proxy Selection** – If configured, **ProxyManager** selects the healthiest node from `PUBLIC_PROXY_LIST` using `getBestProxy()`.
4. **WeChat MP Proxy** – `proxyMpRequest` constructs a browser-mimicking request with forged headers and forwards it to `mp.weixin.qq.com`.
5. **Response Normalization** – Raw WeChat responses are parsed to JSON, reshaped, and returned to the caller.

All network traffic to WeChat MP originates exclusively from the Nitro server, ensuring client IP addresses remain hidden and authentication tokens never reach the browser.

## Component Architecture Breakdown

### Public API Handlers (server/api/public/v1/)

Public endpoints such as [[`server/api/public/v1/article.get.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/server/api/public/v1/article.get.ts)](https://github.com/wechat-article/wechat-article-exporter/blob/master/server/api/public/v1/article.get.ts) serve as the entry point. They validate input parameters (e.g., `fakeid`, `sub`, `begin`, `count`), assemble the query string, and delegate network operations to the proxy utility.

```typescript
// server/api/public/v1/article.get.ts
export default defineEventHandler(async event => {
  const token = await getTokenFromStore(event);      // step 2
  if (!token) return { base_resp: { ret: -1, err_msg: '认证信息无效' } };

  const query = getQuery<AppMsgPublishQuery>(event);
  const resp = await proxyMpRequest({               // step 4
    event,
    method: 'GET',
    endpoint: 'https://mp.weixin.qq.com/cgi-bin/appmsgpublish',
    query: params,
    parseJson: true,
  });
  // ...massage response...
});

```

### CookieStore and Session Management

The [[`server/utils/CookieStore.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/server/utils/CookieStore.ts)](https://github.com/wechat-article/wechat-article-exporter/blob/master/server/utils/CookieStore.ts) module provides **KV-backed persistence** for WeChat authentication tokens. When a user logs in, `proxyMpRequest` writes the session cookie against a server-side `auth-key` identifier using `cookieStore.setCookie(...)`. Subsequent requests retrieve this token via `getTokenFromStore(event)`, which maps the incoming `auth-key` cookie to the stored credentials without exposing sensitive WeChat tokens to clients.

### proxyMpRequest Utility (server/utils/proxy-request.ts)

Located at [[`server/utils/proxy-request.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/server/utils/proxy-request.ts)](https://github.com/wechat-article/wechat-article-exporter/blob/master/server/utils/proxy-request.ts), this utility constructs Requests that mimic genuine WeChat browser sessions:

- **Header spoofing** sets `Referer: https://mp.weixin.qq.com/`, `Origin: https://mp.weixin.qq.com`, and a realistic `User-Agent`.
- **Compression disabled** via `Accept-Encoding: identity` prevents WeChat from returning encoded responses that break JSON parsing.
- **Cookie injection** appends the stored WeChat token to the request headers.
- **Set-Cookie rewriting** intercepts login responses to update the server-side `auth-key` cookie and clean up temporary `uuid` cookies.

```typescript
// server/utils/proxy-request.ts
const headers = new Headers({
  Referer: 'https://mp.weixin.qq.com/',
  Origin: 'https://mp.weixin.qq.com',
  'User-Agent': USER_AGENT,
  'Accept-Encoding': 'identity',
});
if (cookie) headers.set('Cookie', cookie);

```

### ProxyManager and Public Proxy Infrastructure

The [[`utils/download/ProxyManager.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/utils/download/ProxyManager.ts)](https://github.com/wechat-article/wechat-article-exporter/blob/master/utils/download/ProxyManager.ts) maintains a health-aware pool of public proxies defined in [[`config/public-proxy.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/config/public-proxy.ts)](https://github.com/wechat-article/wechat-article-exporter/blob/master/config/public-proxy.ts). The static `PUBLIC_PROXY_LIST` contains 96 proxy URLs spanning domains like `worker-proxy.asia` and `net-proxy.asia`.

`ProxyManager` tracks each proxy's status in a `Map<string, ProxyStatus>` recording:

- `failures` – consecutive error count
- `cooldown` – boolean triggered when `failures >= maxFailures`
- `lastUsed` – timestamp of last assignment
- `totalSuccess`, `totalFailures`, `totalUse` – aggregate statistics

When routing through a proxy, the service calls `proxyManager.getBestProxy()` to select the node with lowest failure rate and freshest cooldown status. After each request, `recordSuccess(proxy)` resets failure counters or `recordFailure(proxy)` increments them and triggers cooldown logic.

## Implementation Deep Dive

### Handler Delegation Pattern

Public handlers never contact WeChat directly. Instead, they validate business logic and pass a configuration object to `proxyMpRequest`:

```typescript
const resp = await proxyMpRequest({
  event,
  method: 'GET',
  endpoint: 'https://mp.weixin.qq.com/cgi-bin/appmsgpublish',
  query: { fakeid: 'xxx', begin: '0', count: '5' },
  cookie: token,        // from CookieStore
  parseJson: true,      // auto-parse response
});

```

### Browser Fingerprinting

The proxy utility ensures WeChat's WAF (Web Application Firewall) recognizes requests as legitimate browser traffic by enforcing specific header combinations required by the WeChat MP platform.

### Proxy Failover Logic

When direct IP access triggers rate limits, the architecture automatically falls back to the public proxy pool. The `ProxyManager` rotates traffic across 96 distinct endpoints, cooling down nodes that return 5xx errors or timeouts until they recover.

## Client Integration Example

Front-end components consume the External API Service using standard `fetch` with credentials included to transmit the `auth-key` cookie:

```typescript
// Front-end Vue composable
export async function loadArticles(fakeid: string) {
  const resp = await fetch(
    `/api/public/v1/article?fakeid=${encodeURIComponent(fakeid)}&size=10`,
    { credentials: 'include' }  // transmits auth-key cookie
  );
  const data = await resp.json();
  if (data.base_resp.ret !== 0) {
    throw new Error(data.base_resp.err_msg);
  }
  return data.articles;
}

```

The server-side pipeline then executes: CookieStore lookup → ProxyManager selection (optional) → WeChat MP request → JSON normalization → Client response.

## Summary

- The **External API Service** acts as a secure gateway under `server/api/public/v1/`, ensuring clients never communicate directly with WeChat MP.
- **CookieStore** ([`server/utils/CookieStore.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/server/utils/CookieStore.ts)) provides KV-backed session persistence using server-side `auth-key` cookies to shield WeChat tokens.
- **proxyMpRequest** ([`server/utils/proxy-request.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/server/utils/proxy-request.ts)) forges browser headers and handles `Set-Cookie` rewriting to maintain session continuity.
- **ProxyManager** ([`utils/download/ProxyManager.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/utils/download/ProxyManager.ts)) load-balances across 96 public proxies defined in [`config/public-proxy.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/config/public-proxy.ts), tracking failures and enforcing cooldown periods.
- All authentication and proxy logic executes exclusively on the Nitro server side, isolating clients from WeChat's API complexity and IP-based rate limiting.

## Frequently Asked Questions

### What is the primary role of the EXTERNAL_API_SERVICE?

The External API Service serves as a **thin gateway** that exposes public HTTP endpoints for WeChat MP data retrieval while keeping all direct WeChat communication server-side. According to the `wechat-article-exporter` source code, this architecture prevents client IP exposure and centralizes authentication management within the Nuxt 3 Nitro layer.

### How does CookieStore maintain WeChat authentication across requests?

**CookieStore** persists WeChat login tokens in a KV store keyed by a server-side `auth-key` cookie. When `getTokenFromStore(event)` is invoked, it reads the client's `auth-key` cookie, retrieves the associated WeChat session from storage, and injects it into the proxied request. This pattern allows the service to maintain long-lived WeChat sessions without exposing sensitive credentials to the browser.

### When does the service route requests through public proxies?

The service routes traffic through **ProxyManager's** public proxy pool when direct connections to `mp.weixin.qq.com` fail due to IP blocking or rate limiting. The `getBestProxy()` method selects proxies based on failure history and cooldown status from the 96-node `PUBLIC_PROXY_LIST`. Failed requests trigger `recordFailure()` to cool down problematic nodes until they recover.

### How does proxyMpRequest mimic legitimate browser traffic?

The `proxyMpRequest` utility constructs Requests with **browser-mimicking headers** including `Referer: https://mp.weixin.qq.com/`, matching `Origin`, realistic `User-Agent`, and `Accept-Encoding: identity` to disable compression. This header fingerprinting ensures WeChat's servers treat the Nitro server as a genuine browser client rather than an automated scraper.