freeCodeCamp「Request Header Parser Microservice」:一个从 HTTP 请求头读取信息的后端微服务项目实战
本文为 freeCodeCamp 课程中「Back-End Development and APIs」认证的第 2 个项目——Request Header Parser Microservice(请求头解析微服务)。你将构建一个功能上与 freeCodeCamp 官方示例应用等价的 JavaScript 全栈应用,核心任务是通过一个 /api/whoami 接口从 HTTP 请求头中解析出访问者的 IP 地址、首选语言和所用软件,并以 JSON 形式返回。读完本文,你会掌握该项目的完整接口契约、测试断言的逐条解读,以及这类后端项目型课程题在 freeCodeCamp 课程体系中的组织方式与提交机制。
项目定位:Back-End Development and APIs 认证的第二个项目
该项目是「Back-End Development and APIs」认证下 5 个项目中的第 2 个。课程的区块结构定义在 back-end-development-and-apis-projects.json 中,challengeOrder 数组明确了项目顺序:
- Timestamp Microservice(
bd7158d8c443edefaeb5bdef) - Request Header Parser Microservice(
bd7158d8c443edefaeb5bdff) - URL Shortener Microservice(
bd7158d8c443edefaeb5bd0e) - Exercise Tracker(
5a8b073d06fa14fcfde687aa) - File Metadata Microservice(
bd7158d8c443edefaeb5bd0f)
课程文件本身是 back-end-development-and-apis-projects/bd7158d8c443edefaeb5bdff.md。其 frontmatter 中的关键字段值得逐一说明:
id: bd7158d8c443edefaeb5bdff——挑战的唯一标识,也是目录中同名.md文件的文件名,freeCodeCamp 的课程体系以该 id 关联挑战文件、结构文件与前端组件;title: Request Header Parser Microservice——展示标题;challengeType: 4——挑战类型。在 challenge-types.ts 中,4对应backEndProject(后端项目型挑战);dashedName: request-header-parser-microservice——由标题派生的 URL 短横线命名,构成访问路径/learn/back-end-development-and-apis/back-end-development-and-apis-projects/request-header-parser-microservice的最后一段。该路径前缀在 cert-and-project-map.ts 中的apiMicroBase常量定义;e2e 测试 hotkeys.spec.ts 中同样硬编码了这条完整学习路径,可视为路径格式的可执行验证。
挑战类型 4 意味着什么:提交方式由 challengeType 决定
从源码结构看,challengeType 不只是一个分类标签,它同时决定了前端如何渲染这个挑战页面、以及完成后如何提交答案:
- 视图类型:challenge-types.ts 中
viewTypes把backEndProject映射为'backend'视图,即以项目说明页面呈现,而非代码编辑器页面; - 提交类型:
submitTypes将backEndProject映射为'project.backEnd',源码注释明确写道:
// requires two urls
// a hosted URL where the app is running live
// project code url like GitHub
[backEndProject]: 'project.backEnd',
也就是说,完成本项目的提交需要两个 URL:一个是应用在线运行的地址(课程测试将直接请求它),另一个是代码仓库地址。这正是该挑战在课程描述中要求"克隆模板仓库本地完成,或自选站点构建器部署"的底层原因——测试系统只对部署后的公开地址发起请求,不检查本地代码。此外,hasNoSolution 函数(challenge-types.ts)将 backEndProject 列入"无标准答案"清单,即课程不提供可直接运行的参考实现,需自行搭建。
在证书层面,cert-and-project-map.ts 将本项目登记在 Back-End Development and APIs 认证下(certSlug: Certification.BackEndDevApis),其 link 指向 ${apiMicroBase}/request-header-parser-microservice,与上述学习路径一致。
核心任务:构建 /api/whoami 接口
课程描述给出的功能目标是:构建一个与 freeCodeCamp 官方示例服务功能相似的 JavaScript 全栈应用。两种完成途径为:
- 克隆官方 boilerplate 仓库(
boilerplate-project-headerparser)并在本地完成项目; - 使用任意的站点构建器完成项目,但必须包含 boilerplate 仓库中的所有文件。
接口契约:三个必须返回的键
课程内嵌的自动化测试(以 fetch 请求部署地址)定义了精确的接口契约。请求 GET /api/whoami 必须返回一个 JSON 对象,且包含以下三个键,每个值都必须非空:
| 返回键 | 数据来源(HTTP 请求头) | 测试断言 |
|---|---|---|
ipaddress |
X-Forwarded-For(经反向代理/CDN 时首选) |
assert(data.ipaddress && data.ipaddress.length > 0) |
language |
Accept-Language |
assert(data.language && data.language.length > 0) |
software |
User-Agent |
assert(data.software && data.software.length > 0) |
三条测试的逻辑完全同构,以下以 IP 地址一条为例,测试代码直接取自课程文件 bd7158d8c443edefaeb5bdff.md:
const response = await fetch(code + '/api/whoami');
if (!response.ok) {
throw new Error(await response.text());
}
const data = await response.json();
assert(data.ipaddress && data.ipaddress.length > 0);
其中 code 变量即你在提交时填写的应用托管 URL。可以从测试代码中提炼出几条硬性要求:
- 接口必须返回 2xx 状态码,否则
response.ok为 false 直接抛错; - 响应体必须是可被
response.json()解析的合法 JSON,这隐含要求设置Content-Type: application/json(Express 中用res.json()即可满足); - 三个键的值必须存在且
length > 0——注意是length判断,意味着空字符串也会判负。
请求头解析的实现要点
按 HTTP 规范,三个键应分别读取如下请求头,这正是本项目考察的核心知识点:
- IP 地址:客户端真实 IP 通常在
X-Forwarded-For头中(应用置于反向代理之后时);X-Forwarded-For是逗号分隔的代理链,第一个值才是发起客户端的 IP;无该头时可退回连接层的req.ip。 - 首选语言:读取
Accept-Language头。注意该头可能是带质量系数的列表(如en-US,en;q=0.9,zh-CN;q=0.8),测试只要求非空,因此返回原值或其首段均可通过。 - 所用软件:读取
User-Agent头,通常形如浏览器名称加版本信息,直接返回原值即可。
一个满足契约的最小 Express 实现骨架如下(供理解测试如何跑通,而非完整参考答案):
app.get('/api/whoami', (req, res) => {
const ip = (req.headers['x-forwarded-for'] || req.ip).split(',')[0].trim();
res.json({
ipaddress: ip,
language: req.headers['accept-language'],
software: req.headers['user-agent']
});
});
实现时值得注意的边界情况:X-Forwarded-For 可能缺失(直连部署时为空),需有回退逻辑;Accept-Language 理论上也可能缺失,但真实浏览器几乎总会携带。由于测试只断言"非空",这类细节决定你的接口在异常请求下是否健壮。
防作弊断言:必须提交自己的项目
测试文件的第一条断言(bd7158d8c443edefaeb5bdff.md)是防作弊检查:
assert(
!/.*\/request-header-parser-microservice\.freecodecamp\.rocks/.test(
code
)
);
课程描述中给出的官方示例地址属于 *.freecodecamp.rocks 域名。这条断言确保你提交的托管 URL 不是官方示例服务本身——正则对 code(你填写的 URL)做子串匹配,只要 URL 中出现示例服务路径就判负。课程描述也明确提示:"You should provide your own project, not the example URL."
从仓库代码看该项目的可验证链路
本课程题在仓库中的关联路径形成了完整的可验证链路,可供读者自行深入核对:
- 挑战内容与测试断言:curriculum/challenges/english/blocks/back-end-development-and-apis-projects/bd7158d8c443edefaeb5bdff.md
- 区块结构与项目排序:curriculum/structure/blocks/back-end-development-and-apis-projects.json
- 认证归属与学习路径映射:client/config/cert-and-project-map.ts
- 挑战类型 4 的渲染与提交语义:packages/shared/src/config/challenge-types.ts
- e2e 测试中的完整学习路径:e2e/hotkeys.spec.ts
小结
Request Header Parser Microservice 是 freeCodeCamp 后端认证中体量最小但契约最精确的项目:一个 GET /api/whoami 接口,从 X-Forwarded-For、Accept-Language、User-Agent 三个请求头取值,以 JSON 返回 ipaddress、language、software 三个非空键,配合 2xx 状态码即通过全部功能断言。完成它需要掌握 Express 路由、请求头读取与 JSON 响应,并完成一次真实的公网部署——这也是该课程用"提交托管 URL 供服务器主动探测"这种设计,把 HTTP 协议知识落到实战的意图所在。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00