# CFnew Dual-Mode Request Handling System: Routing API and Proxy Traffic in Cloudflare Workers

> Explore CFnew's dual-mode request handling. This Cloudflare Worker routes API traffic and proxy requests, dynamically generating configurations based on User-Agent headers. Learn how it works.

- Repository: [byJoey/cfnew](https://github.com/byJoey/cfnew)
- Tags: deep-dive
- Published: 2026-05-23

---

**CFnew’s Cloudflare Worker implements a dual-mode request handling system that inspects incoming request paths to route `/api/*` traffic to a management API while processing all other requests as subscription proxy traffic that dynamically generates client configurations based on User-Agent headers.**

The `byJoey/cfnew` repository deploys a single Cloudflare Worker capable of serving two distinct traffic patterns without requiring separate services. This architecture consolidates configuration management and subscription generation into one edge function, utilizing KV storage for persistent settings and query-string parameters for runtime overrides.

## How the Dual-Mode Dispatcher Works

The request handler registered via `addEventListener('fetch', …)` in [`src/worker.js`](https://github.com/byJoey/cfnew/blob/main/src/worker.js) acts as a traffic router. It evaluates the `url.pathname` and `request.method` to determine which processing pipeline to invoke.

- **API Mode**: Triggered when `url.pathname.startsWith('/api/')`. The worker delegates to `handleApi(request)` to process CRUD operations on preferred IPs and global settings.
- **Proxy Mode**: Activated for all non-API paths. The worker delegates to `handleProxy(request)` to generate VLESS/Trojan URLs or subscription files.

If a request uses a method other than `GET` and does not target the `/api/` namespace, the dispatcher immediately returns a **405 Method Not Allowed** response, enforcing read-only access for subscription endpoints.

## API Mode: Configuration Management

When operating in API mode, the worker exposes endpoints such as `POST /api/preferred-ips` and `GET /api/preferred-ips`. These handlers parse JSON payloads, validate optional API access flags stored in the KV namespace `C`, and mutate configuration state.

The API handler supports adding, deleting, and listing preferred proxy IPs with custom names and ports. After updating the KV store, it returns a JSON response containing `{ success: true, count: … }` confirming the operation.

## Proxy Mode: Subscription Generation

Proxy mode handles traffic from clients like **Clash**, **Surge**, **Sing-Box**, and **Loon**. The worker inspects the **User-Agent** header to infer the client type and format requirements. Based on this detection, it dynamically constructs YAML or JSON subscription files, or returns individual WebSocket-compatible VLESS/Trojan URLs (`wss://…`).

The proxy handler first loads the cached configuration from the KV namespace `C`, then applies any per-node overrides specified in the request URL before generating the final output.

## Configuration Cache and KV Storage

Both modes share a common **KV-based configuration cache** bound to the namespace `C` as defined in [`wrangler.toml`](https://github.com/byJoey/cfnew/blob/main/wrangler.toml). This cache stores:

- Global defaults (UUID, proxy IP lists, SOCKS5 endpoints)
- Per-node preference tables
- API access flags

Centralizing state in KV allows the worker to maintain consistency between administrative changes made via the API and subscription generation requests served through the proxy handler.

## Per-Node Overrides via Query Parameters

The proxy handler interprets URL query parameters as runtime configuration overrides that take precedence over KV-stored values. Supported parameters include:

- `p=` – Custom proxy IP and port (e.g., `p=1.1.1.1:443`)
- `wk=` – WebSocket path overrides
- `s=` – Security type modifications
- `rm=` – Region mapping adjustments
- `ed=` – Early data/WebSocket0-RTT settings
- `alpn=` – TLS ALPN values (e.g., `alpn=h3,h2`)
- `ech=` – Encrypted Client Hello configuration

These parameters enable dynamic node customization without redeploying the worker or modifying persistent storage.

## Implementation Files and Architecture

The dual-mode logic is distributed across the following logical modules referenced in the deployment configuration:

| File | Responsibility |
|------|----------------|
| [`wrangler.toml`](https://github.com/byJoey/cfnew/blob/main/wrangler.toml) | Binds the KV namespace `C` and defines the worker entry point |
| [`src/worker.js`](https://github.com/byJoey/cfnew/blob/main/src/worker.js) | Contains the `fetch` event listener and dispatch logic routing between API and proxy modes |
| [`src/api.js`](https://github.com/byJoey/cfnew/blob/main/src/api.js) | Implements `handleApi(request)` for JSON API responses and KV mutations |
| [`src/proxy.js`](https://github.com/byJoey/cfnew/blob/main/src/proxy.js) | Implements `handleProxy(request)` for User-Agent detection and subscription generation |
| [`src/config.js`](https://github.com/byJoey/cfnew/blob/main/src/config.js) | Centralizes default values, environment variable parsing, and region mapping tables |

While the production build may compile these into a single script, the source structure maintains this separation of concerns.

## Practical Usage Examples

### Calling the Management API

```javascript
// POST to /api/preferred-ips to add a new preferred node
fetch('https://my-worker.workers.dev/123e4567/api/preferred-ips', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ 
    ip: '1.2.3.4', 
    port: 443, 
    name: '香港节点' 
  })
})
.then(r => r.json())
.then(console.log);
// Response: { success: true, count: 5 }

```

### Generating a Clash Subscription

```javascript
// Standard proxy request triggers subscription generation
fetch('https://my-worker.workers.dev/123e4567?ed=2048&p=1.1.1.1')
  .then(r => r.text())
  .then(yaml => {
    // yaml contains Clash-compatible configuration
    console.log(yaml);
  });

```

### Applying Per-Node Overrides

```javascript
// Request with query overrides for custom proxy settings
const link = 'https://my-worker.workers.dev/123e4567?ed=2048&p=proxy.example.com:443&alpn=h3,h2';
fetch(link)
  .then(r => r.text())
  .then(vlessUrl => {
    // Returns VLESS URL with embedded custom parameters
    console.log(vlessUrl);
  });

```

## Summary

- The **dual-mode request handling system** in `byJoey/cfnew` uses path-based routing to separate API management from subscription proxy functionality within a single Cloudflare Worker.
- **API mode** handles `/api/*` paths for CRUD operations on KV-stored configurations, requiring validation and supporting JSON payloads.
- **Proxy mode** processes all other requests, detecting client types via **User-Agent** headers to generate appropriate subscription formats (YAML for Clash, etc.).
- Both modes share the **KV namespace `C`** for persistent configuration, enabling real-time updates via API that immediately affect subsequent proxy responses.
- **Query parameters** (`p=`, `alpn=`, `ed=`, etc.) allow runtime per-node overrides without modifying stored configuration.

## Frequently Asked Questions

### How does CFnew decide whether to use API mode or proxy mode?

The worker inspects `url.pathname` in the `fetch` event handler located in [`src/worker.js`](https://github.com/byJoey/cfnew/blob/main/src/worker.js). If the path starts with `/api/`, it routes to `handleApi(request)`. Otherwise, it routes to `handleProxy(request)` after verifying the request method is `GET` (returning 405 for other methods).

### What configuration options can be overridden via URL parameters?

The proxy handler recognizes several query parameters for runtime customization: `p` for proxy IP/port, `alpn` for TLS ALPN, `ed` for early data settings, `wk` for WebSocket paths, `s` for security type, and `rm` for region mapping. These overrides take precedence over values stored in the KV namespace `C`.

### Which clients are supported by the proxy mode subscription generator?

The worker detects **Clash**, **Surge**, **Sing-Box**, **Loon**, and standard **VLESS/Trojan** clients by parsing the User-Agent header. Based on this detection, it generates the appropriate format: YAML for Clash, text for Surge, JSON for Sing-Box, or plain URLs for direct proxy clients.

### Where is the KV configuration stored and accessed?

The worker binds to a KV namespace named **`C`** configured in [`wrangler.toml`](https://github.com/byJoey/cfnew/blob/main/wrangler.toml). Both [`src/api.js`](https://github.com/byJoey/cfnew/blob/main/src/api.js) (API mode) and [`src/proxy.js`](https://github.com/byJoey/cfnew/blob/main/src/proxy.js) (proxy mode) read from and write to this namespace to share global settings, preferred IP lists, and per-node configurations across all requests.