纯前端转全栈 Day 1:我从第一个 NestJS 接口开始

纯前端转全栈 Day 1:我从第一个 NestJS 接口开始

我是一个前端开发,之前更多关注的是:页面怎么展示、组件怎么拆、状态怎么管理、接口怎么联调。

但最近我越来越明显地感受到,只会写页面已经不太够了。很多业务并不是把 UI 做出来就结束,而是需要理解一个功能从页面、接口、数据、权限到部署的完整链路。

所以我决定开始系统补服务端能力。

我的目标不是立刻成为传统后端,而是先成为一个能独立完成业务闭环的全栈型前端。

为什么从 NestJS 开始?

我选择从 NestJS 开始,是因为它基于 Node.js 和 TypeScript,对前端来说学习成本相对低一些。

而且它的很多概念,比如:

  • Controller
  • Service
  • Module
  • 依赖注入

和我之前接触过的 Angular 有一定相似之处。

对于一个前端来说,用 TypeScript 体系切入服务端,是一条成本相对更低的路线。

今天完成了什么?

今天我完成了第一个 NestJS 项目,并写了两个接口。

第一个接口是:

http 复制代码
GET /

返回:

css 复制代码
Hello Content Studio API

第二个接口是:

bash 复制代码
GET /health

返回:

json 复制代码
{
  "status": "ok",
  "service": "content-studio-api"
}

虽然这两个接口都很简单,但它让我第一次从"调用接口的人",变成了"写接口的人"。

我理解的 NestJS 请求链路

今天我理解到,NestJS 里最基础的请求链路是:

markdown 复制代码
浏览器发起请求
        ↓
Controller 接收请求
        ↓
Controller 调用 Service
        ↓
Service 处理逻辑并返回数据
        ↓
NestJS 把结果响应给浏览器

也就是说:

  • Controller 更像是接口入口,负责接住请求
  • Service 更像是真正处理业务逻辑的地方
  • Module 负责把 Controller 和 Service 组织在一起

今天的接口很简单,所以暂时看不出分层的必要性。

但我能理解,后面如果要做用户注册、登录、内容创建、数据库查询,就不适合把所有逻辑都写在 Controller 里。

今天最困惑的点:constructor 和依赖注入

今天最让我困惑的是 constructor 和依赖注入。

一开始我看到这句代码:

typescript 复制代码
constructor(private readonly appService: AppService) {}

会有点不理解:

我明明没有 new AppService(),为什么 this.appService 可以直接使用?

后来我把它理解成:

AppController 需要 AppService,但它不自己创建 AppService,而是在 constructor 里声明:

我需要一个 AppService。

只要 AppService 已经在 Moduleproviders 里注册,NestJS 就会帮我们创建它,并注入到 AppController 里。

所以依赖注入的核心不是某个神秘语法,而是一种分工方式:

类不负责自己创建依赖,而是声明自己需要什么;框架负责创建和管理这些依赖。

换句话说,Controller 不需要关心 Service 是怎么被创建出来的,它只需要声明自己要用这个 Service。

今天遇到的环境问题

今天还遇到了一个环境问题。

我使用 pnpm 安装依赖时,出现了类似这样的提示:

csharp 复制代码
[ERR_PNPM_IGNORED_BUILDS] Ignored build scripts

后来通过执行:

复制代码
pnpm approve-builds

允许下面两个包执行构建脚本:

less 复制代码
@nestjs/core
@swc/core

项目才正常启动。

这个问题也让我意识到,前端或全栈开发里,环境问题本身也是学习的一部分。

有时候并不是代码写错了,而是包管理器、依赖构建、Node 版本、脚本权限这些地方出了问题。

重新理解 localhost

今天我还重新理解了一下 localhost

以前做前端开发时,我经常会在浏览器里访问 localhost,比如:

arduino 复制代码
http://localhost:5173

或者:

arduino 复制代码
http://localhost:3000

以前我只是知道它能访问本地服务,但今天我意识到:

localhost 并不是某个固定的服务器地址,而是"当前运行环境里的自己"。

当我在 Mac 浏览器里访问:

arduino 复制代码
http://localhost:3000

请求的是我这台 Mac 上 3000 端口的 NestJS 服务。

但如果同样的代码部署到线上,真实用户浏览器里的 localhost 就会变成用户自己的电脑,而不是我的服务器。

所以线上接口地址不能写死成:

arduino 复制代码
http://localhost:3000

而应该通过环境变量区分不同环境:

复制代码
开发环境:localhost
测试环境:test-api.xxx.com
生产环境:api.xxx.com

127.0.0.1 和 0.0.0.0

今天也初步理解了 127.0.0.10.0.0.0 的区别。

127.0.0.1 更像是本机内部访问自己。

0.0.0.0 常用于服务端监听所有网络接口,让局域网内其他设备也可能访问到这个服务。

比如:

csharp 复制代码
await app.listen(3000, '0.0.0.0');

可以先理解成:

这个服务不只监听本机内部访问,也愿意接受来自其他网络入口的请求。

这让我意识到,后端开发里一个很基础但很重要的能力,是理解:

服务运行在哪里?请求从哪里来?最后又会被路由到哪里去?

今天的收获

今天的收获不是写了多少代码,而是理解了一个后端服务最基础的运行链路:

复制代码
请求从哪里进来
谁接收请求
谁处理逻辑
结果怎么返回
服务运行在哪里
localhost 到底指向谁

以前我更多是"调用接口的人"。

今天开始,我第一次真正从服务端视角去看一个请求。

明天准备做什么?

明天我准备继续做第一个 CRUD。

我会从内容管理业务开始,尝试实现:

  • 内容列表
  • 内容详情
  • 新增内容
  • 编辑内容
  • 删除内容

也就是从一个真实的小业务开始,继续理解后端接口是怎么设计和实现的。

相关推荐
Lee川2 小时前
从零解剖一个 AI Agent Tool是如何实现的
前端·人工智能·后端
wangruofeng3 小时前
Playwright 深度调研:为什么它成了浏览器自动化的新底座
前端·测试
李白的天不白5 小时前
SSR服务端渲染
前端
卷帘依旧6 小时前
SSE(Server-Sent Events)完全指南
前端
码云之上6 小时前
万星入坞:我们如何用三层插件体系干掉巨石应用
前端·架构·前端框架
kyriewen6 小时前
一口气讲清楚 Monorepo、Turborepo、pnpm、Changesets 到底是什么?
前端·架构·前端工程化
IT_陈寒7 小时前
React性能优化踩的坑,这个错你可能也会犯
前端·人工智能·后端
zhangxingchao7 小时前
AI应用开发三:RAG技术与应用
前端·人工智能·后端
摘星小杨7 小时前
如何在前端循环调取接口,实时查询数据
开发语言·前端·javascript