# How the Nitro Server-Side Proxy Handles WeChat API Requests

> Learn how the Nitro server-side proxy securely handles WeChat API requests by forwarding them with forged headers, managing cookies, and sanitizing responses to prevent CORS issues.

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

---

**The Nitro server-side proxy acts as a secure intermediary by forwarding client requests to WeChat MP endpoints with forged headers, managing authentication cookies via an LRU-backed store, and sanitizing responses to prevent CORS issues.**

The `wechat-article/wechat-article-exporter` repository leverages Nuxt 3's Nitro engine to circumvent browser restrictions when interfacing with the WeChat public platform (MP). All WeChat API calls flow through a dedicated server-side proxy that normalizes headers, maintains authentication state, and cleans response cookies before they reach the client.

## Request Flow Architecture

The proxy implementation centers on the `proxyMpRequest()` function defined in **[[`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)**. When the front-end invokes a Nitro API route (e.g., `server/api/web/mp/...`), execution passes through this utility, which orchestrates header preparation, cookie retrieval, and response sanitization.

### Header Preparation and Security

Inside `proxyMpRequest`, the function constructs a `Headers` object mandatory for WeChat acceptance:

- **Referer** and **Origin** are hard-coded to `https://mp.weixin.qq.com/` to satisfy WeChat's domain validation
- **User-Agent** is injected from the constant 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)**
- **Accept-Encoding** is set to `identity` to prevent compression, ensuring the response body can be cloned and processed reliably

These headers are applied to a native `Request` object before forwarding.

### Cookie Handling and Authentication

The proxy retrieves stored credentials through **[`getCookieFromStore`](https://github.com/wechat-article/wechat-article-exporter/blob/master/server/utils/CookieStore.ts#L27-L49)** in **[[`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)**. The logic branches based on the incoming request:

- If the caller explicitly provides a `cookie` value in the options object, that string is used directly
- Otherwise, the utility inspects the `X-Auth-Key` header or `auth-key` cookie, then fetches the associated `AccountCookie` from either an in-memory LRU cache or the persistent KV store

The resulting cookie string is attached to the outgoing request, allowing the proxy to impersonate a logged-in browser session.

### Request Construction and Forwarding

For `POST` requests, the proxy URL-encodes the body as `application/x-www-form-urlencoded` before constructing the final `Request` instance. The endpoint URL may be extended with query parameters supplied via `options.query`. When the environment variable `NUXT_DEBUG_MP_REQUEST` is set, the fully formed request is logged for debugging.

Because the proxy executes on the server, it uses `fetch()` to communicate with WeChat endpoints without triggering browser CORS preflight checks or cookie restrictions.

### Response Processing and Action Handlers

After receiving the WeChat response, the proxy executes action-specific logic based on `options.action`:

- **`start_login`** – Extracts the temporary `uuid` cookie set by the WeChat login page
- **`login`** – Parses the JSON body to extract `redirect_url`, retrieves the `token` parameter, and persists the complete cookie set via **[`cookieStore.setCookie`](https://github.com/wechat-article/wechat-article-exporter/blob/master/server/utils/CookieStore.ts#L61-L68)**. It returns two `Set-Cookie` headers to the client: a new `auth-key` (4-day expiry) and an expired `uuid` to clear the temporary session
- **`switch_account`** – Appends a `switch_account=1` cookie to signal account context changes

The proxy strips all original `Set-Cookie` headers from WeChat to prevent client-side exposure, injecting only the sanitized proxy-managed cookies.

## Cookie Store Mechanics

The **[`CookieStore`](https://github.com/wechat-article/wechat-article-exporter/blob/master/server/utils/CookieStore.ts)** utility maintains state through an LRU-style in-memory `Map<string, AccountCookie>` backed by a KV storage layer ([`server/kv/cookie.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/server/kv/cookie.ts)).

Each `AccountCookie` instance parses raw `Set-Cookie` strings into structured `CookieEntity` objects and can serialize them back into HTTP-ready header strings via the `toString()` method. When `setCookie` is invoked, the update is written to both the in-memory cache for immediate subsequent lookups and the KV store for persistence across server restarts.

## Practical Implementation Examples

The following patterns demonstrate how to invoke the proxy within Nitro API routes:

```typescript
// server/api/articles/list.get.ts
import { proxyMpRequest } from '@/server/utils/proxy-request';

export default defineEventHandler(async (event) => {
  const authKey = getCookie(event, 'auth-key');
  
  return proxyMpRequest({
    endpoint: 'https://mp.weixin.qq.com/cgi-bin/home',
    method: 'GET',
    action: 'fetch_articles',
    query: { t: 'home/index', lang: 'zh_CN' },
    cookie: undefined, // pulled automatically from store via authKey
    event,
    parseJson: true,
  });
});

```

```typescript
// server/api/auth/login.post.ts
export default defineEventHandler(async (event) => {
  const body = await readBody(event);
  
  return proxyMpRequest({
    endpoint: 'https://mp.weixin.qq.com/cgi-bin/login',
    method: 'POST',
    action: 'login',
    body: { username: body.user, pwd: body.pass },
    event,
    parseJson: false, // returns redirect URL in body
  });
});

```

## Summary

- **CORS Bypass**: The Nitro server-side proxy executes requests outside browser constraints, eliminating preflight issues when contacting `mp.weixin.qq.com`
- **Header Forgery**: Fixed `Referer`, `Origin`, and `User-Agent` headers convince WeChat servers the request originates from an official domain
- **Authentication Management**: The `CookieStore` utility persists sessions via an LRU cache backed by KV storage, keyed by `auth-key` tokens
- **Login Flow Support**: Special actions (`start_login`, `login`) handle UUID extraction, token parsing from `redirect_url`, and cookie rotation
- **Security Sanitization**: Original WeChat `Set-Cookie` headers are stripped and replaced with proxy-controlled equivalents to prevent credential leakage

## Frequently Asked Questions

### Why does the proxy need to spoof Referer and Origin headers?

WeChat's MP platform validates the source of incoming requests to prevent CSRF and unauthorized scraping. By setting both `Referer` and `Origin` to `https://mp.weixin.qq.com/`, the Nitro server-side proxy satisfies these security checks, allowing the API to accept the request as if it came from an authenticated browser session on the official domain.

### How does the CookieStore handle session persistence across server restarts?

The `CookieStore` maintains a hot in-memory `Map` for low-latency lookups during active requests, but delegates long-term storage to a KV backend defined in [`server/kv/cookie.ts`](https://github.com/wechat-article/wechat-article-exporter/blob/main/server/kv/cookie.ts). When `setCookie` is called, the utility writes to both layers simultaneously, ensuring that even if the Nitro process restarts, the `auth-key` can still retrieve the associated `AccountCookie` from persistent storage.

### What is the difference between the `uuid` and `auth-key` cookies?

The `uuid` cookie is a temporary identifier generated during the `start_login` phase that tracks the initial login session on WeChat's servers. Upon successful authentication (`login` action), the proxy exchanges this temporary cookie for a permanent session identified by `auth-key`, which is stored in the `CookieStore` and valid for four days. The proxy then instructs the client to expire the `uuid` cookie since it is no longer needed.

### Why must Accept-Encoding be set to identity instead of allowing compression?

The proxy disables compression by forcing `Accept-Encoding: identity` because the Nitro server needs to potentially clone and inspect the response body before forwarding it to the client. Compressed responses (gzip/deflate) can only be read once and cannot be trivially cloned for logging or JSON parsing without consuming the stream, which would break subsequent transmission to the client.