You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular 17部署Cloudflare Workers/Pages时如何传递HTTP状态码?

在Cloudflare Pages/Worker中为Angular SSR应用传递HTTP状态码与自定义请求头

我正尝试在Cloudflare Pages/Worker上部署Angular应用,已通过Cloudflare CLI生成了一个Angular 17测试应用,其server.ts代码如下:

import { renderApplication } from "@angular/platform-server";
import bootstrap from "./src/main.server";

interface Env {
    ASSETS: { fetch: typeof fetch };
}

// We attach the Cloudflare `fetch()` handler to the global scope
// so that we can export it when we process the Angular output.
// See tools/bundle.mjs
async function workerFetchHandler(request: Request, env: Env) {
    const url = new URL(request.url);
    console.log("render SSR", url.href);

    // Get the root `index.html` content.
    const indexUrl = new URL("/", url);
    const indexResponse = await env.ASSETS.fetch(new Request(indexUrl));
    const document = await indexResponse.text();

    const content = await renderApplication(bootstrap, {
        document,
        url: url.pathname,
    });

    // console.log("rendered SSR", content);
    return new Response(content, indexResponse);
}

export default {
    fetch: (request: Request, env: Env) =>
        (globalThis as any)["__zone_symbol__Promise"].resolve(
            workerFetchHandler(request, env)
        ),
};

上述代码使用renderApplication返回字符串输出,我想了解如何从Angular应用传递HTTP状态码(如404页面未找到)或自定义请求特定头信息。我已查看过Stack Overflow上的相关链接,但不确定在Cloudflare Pages/Worker环境下该如何实现。


解决方案

1. 传递HTTP状态码(如404)

通过Angular的TransferState在组件与Cloudflare Worker之间传递状态标记,再在Worker中修改响应状态码:

步骤1:在Angular组件中标记状态

在404等错误组件中,注入TransferState并设置状态码:

// src/app/not-found/not-found.component.ts
import { Component, OnInit } from '@angular/core';
import { TransferState, makeStateKey } from '@angular/platform-browser';

const STATUS_CODE_KEY = makeStateKey<number>('statusCode');

@Component({
  selector: 'app-not-found',
  templateUrl: './not-found.component.html',
})
export class NotFoundComponent implements OnInit {
  constructor(private transferState: TransferState) {}

  ngOnInit() {
    this.transferState.set(STATUS_CODE_KEY, 404);
  }
}

步骤2:在Worker中读取并设置响应码

修改server.ts中的workerFetchHandler,创建TransferState实例并传入渲染配置,最后读取状态码修改响应:

import { renderApplication, ɵSERVER_CONTEXT } from "@angular/platform-server";
import bootstrap from "./src/main.server";
import { TransferState, makeStateKey } from '@angular/platform-browser';

const STATUS_CODE_KEY = makeStateKey<number>('statusCode');

interface Env {
    ASSETS: { fetch: typeof fetch };
}

async function workerFetchHandler(request: Request, env: Env) {
    const url = new URL(request.url);
    console.log("render SSR", url.href);

    const indexUrl = new URL("/", url);
    const indexResponse = await env.ASSETS.fetch(new Request(indexUrl));
    const document = await indexResponse.text();

    // 创建TransferState实例
    const transferState = new TransferState();
    
    const content = await renderApplication(bootstrap, {
        document,
        url: url.pathname,
        providers: [
            { provide: TransferState, useValue: transferState },
            { provide: ɵSERVER_CONTEXT, useValue: 'cloudflare-worker' }
        ]
    });

    // 获取状态码,默认200
    const statusCode = transferState.get(STATUS_CODE_KEY, 200);

    // 复制原响应头并修改状态码
    const responseHeaders = new Headers(indexResponse.headers);
    return new Response(content, {
        status: statusCode,
        headers: responseHeaders
    });
}

export default {
    fetch: (request: Request, env: Env) =>
        (globalThis as any)["__zone_symbol__Promise"].resolve(
            workerFetchHandler(request, env)
        ),
};

2. 传递自定义请求头

同样借助TransferState传递头信息,再在Worker中添加到响应:

步骤1:在Angular组件中传递自定义头

// src/app/some-component/some-component.ts
import { Component, OnInit } from '@angular/core';
import { TransferState, makeStateKey } from '@angular/platform-browser';

const CUSTOM_HEADERS_KEY = makeStateKey<Record<string, string>>('customHeaders');

@Component({
  selector: 'app-some-component',
  templateUrl: './some-component.component.html',
})
export class SomeComponent implements OnInit {
  constructor(private transferState: TransferState) {}

  ngOnInit() {
    this.transferState.set(CUSTOM_HEADERS_KEY, {
      'X-Custom-Header': 'Cloudflare-Worker-Angular',
      'X-Content-Type-Options': 'nosniff'
    });
  }
}

步骤2:在Worker中添加自定义头到响应

修改workerFetchHandler,读取自定义头并添加到响应:

async function workerFetchHandler(request: Request, env: Env) {
    // ... 其他代码 ...

    const transferState = new TransferState();
    
    const content = await renderApplication(bootstrap, {
        document,
        url: url.pathname,
        providers: [
            { provide: TransferState, useValue: transferState },
            { provide: ɵSERVER_CONTEXT, useValue: 'cloudflare-worker' }
        ]
    });

    const statusCode = transferState.get(STATUS_CODE_KEY, 200);
    const customHeaders = transferState.get(CUSTOM_HEADERS_KEY, {});

    const responseHeaders = new Headers(indexResponse.headers);
    // 批量添加自定义头
    Object.entries(customHeaders).forEach(([key, value]) => {
        responseHeaders.set(key, value);
    });

    return new Response(content, {
        status: statusCode,
        headers: responseHeaders
    });
}

备选方案:直接捕获路由错误

如果不需要渲染错误组件,可在路由守卫中抛出带状态码的错误,再在Worker中捕获:

// src/app/app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes, CanActivateFn } from '@angular/router';
import { NotFoundComponent } from './not-found/not-found.component';

const authGuard: CanActivateFn = (route, state) => {
  if (!someCondition) {
    throw { status: 403, message: 'Forbidden' };
  }
  return true;
};

const routes: Routes = [
  // ... 其他路由 ...
  { path: '**', component: NotFoundComponent },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

在server.ts中捕获错误并设置响应:

async function workerFetchHandler(request: Request, env: Env) {
    // ... 其他代码 ...

    let statusCode = 200;
    let content;

    try {
        content = await renderApplication(bootstrap, {
            document,
            url: url.pathname,
        });
    } catch (err: any) {
        if (err.status) {
            statusCode = err.status;
            // 可加载预定义的错误页面
            const errorIndexResponse = await env.ASSETS.fetch(new Request('/404.html'));
            content = await errorIndexResponse.text();
        }
    }

    const responseHeaders = new Headers(indexResponse.headers);
    return new Response(content, {
        status: statusCode,
        headers: responseHeaders
    });
}

内容的提问来源于stack exchange,提问作者Naveed Ahmed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 08:22:44