2個(gè)小時(shí)1.5w字| React & Golang 全棧微服務(wù)實(shí)戰(zhàn)
- 前言
- Golang 入門教程
- Kratos 微服務(wù)框架入門
- React 入門教程
- Next.js 入門教程
- 容器知識(shí)入門教程
- 全棧博客案例
前言
本文分為6個(gè)小節(jié),帶你全方位入門 React & Golang 微服務(wù)全棧開發(fā)。
- golang
- kratos
- react
- next.js
- docker
- 博客案例
每一個(gè)小節(jié)均有豐富的代碼案例,倉庫地址如下:https://github.com/BaiZe1998/go-learning

Golang|AI 主題知識(shí)星球:白澤說 試運(yùn)營當(dāng)中,添加 wx:baize_talk02 咨詢,免費(fèi)加入。

Golang 入門教程
1. 下載與環(huán)境配置
安裝 Go
Windows 安裝
- 訪問 Go 官方下載頁面
- 下載 Windows 安裝包 (MSI)
- 運(yùn)行安裝程序,按照提示完成安裝
- 安裝完成后,打開命令提示符,輸入
go version確認(rèn)安裝成功
macOS 安裝
- 訪問 Go 官方下載頁面
- 下載 macOS 安裝包 (PKG)
- 運(yùn)行安裝程序,按照提示完成安裝
- 或者使用 Homebrew:
brew install go - 安裝完成后,打開終端,輸入
go version確認(rèn)安裝成功
Linux 安裝
-
訪問 Go 官方下載頁面
-
下載對(duì)應(yīng)的 Linux 壓縮包
-
解壓到
/usr/local:sudo tar -C /usr/local -xzf go1.x.x.linux-amd64.tar.gz -
添加環(huán)境變量到
~/.profile或~/.bashrc:export PATH=$PATH:/usr/local/go/bin -
使環(huán)境變量生效:
source ~/.profile或source ~/.bashrc -
驗(yàn)證安裝:
go version
理解 GOROOT 和 GOPATH
GOROOT
GOROOT 是 Go 語言的安裝目錄,它包含了 Go 標(biāo)準(zhǔn)庫、編譯器、工具等。安裝 Go 時(shí)會(huì)自動(dòng)設(shè)置這個(gè)環(huán)境變量。
-
作用:告訴 Go 工具鏈在哪里可以找到 Go 的標(biāo)準(zhǔn)庫和工具
-
默認(rèn)位置:
- Windows:
C:\go - macOS/Linux:
/usr/local/go或 Homebrew 安裝位置
- Windows:
-
查看 GOROOT:
go env GOROOT -
手動(dòng)設(shè)置(通常不需要,除非安裝在非標(biāo)準(zhǔn)位置):
- Windows: 添加系統(tǒng)環(huán)境變量
GOROOT=C:\path\to\go - macOS/Linux: 在
~/.profile或~/.bashrc中添加export GOROOT=/path/to/go
- Windows: 添加系統(tǒng)環(huán)境變量
GOPATH
GOPATH 是 Go 的工作目錄,用于存放 Go 代碼、包和依賴等。
-
作用:
- 在 Go Modules 出現(xiàn)前(Go 1.11之前),所有 Go 項(xiàng)目必須位于 GOPATH 內(nèi)
- 在 Go Modules 時(shí)代,GOPATH 主要用于存儲(chǔ)下載的依賴包和編譯后的二進(jìn)制文件
-
默認(rèn)位置:
- Windows:
%USERPROFILE%\go(例如:C:\Users\YourName\go) - macOS/Linux:
$HOME/go(例如:/home/username/go或/Users/username/go)
- Windows:
-
GOPATH 目錄結(jié)構(gòu):
src: 存放源代碼(如你的項(xiàng)目和依賴包的源碼)pkg: 存放編譯后的包文件bin: 存放編譯后的可執(zhí)行文件
-
設(shè)置多個(gè) GOPATH:
可以設(shè)置多個(gè)目錄,用冒號(hào)(Unix)或分號(hào)(Windows)分隔# Unix/macOS export GOPATH=$HOME/go:$HOME/projects/go # Windows set GOPATH=%USERPROFILE%\go;D:\projects\go
Go Modules 與 GOPATH 的關(guān)系
從 Go 1.11 開始,Go 引入了 Go Modules 作為官方的依賴管理解決方案,逐漸弱化了 GOPATH 的作用:
-
Go Modules 模式下:
- 項(xiàng)目可以位于任何目錄,不必在 GOPATH 內(nèi)
- 依賴通過
go.mod文件管理,而不是通過 GOPATH 目錄結(jié)構(gòu) - 下載的依賴緩存在
$GOPATH/pkg/mod目錄 - 編譯的命令仍安裝到
$GOPATH/bin
-
環(huán)境變量 GO111MODULE:
GO111MODULE=off: 禁用模塊支持,使用 GOPATH 模式GO111MODULE=on: 啟用模塊支持,忽略 GOPATHGO111MODULE=auto: 在 GOPATH 內(nèi)禁用模塊支持,在 GOPATH 外啟用模塊支持
查看和設(shè)置 Go 環(huán)境變量
# 查看所有 Go 環(huán)境變量
go env
# 查看特定環(huán)境變量
go env GOPATH
go env GOROOT
# 設(shè)置環(huán)境變量(Go 1.14+)
go env -w GOPATH=/custom/path
配置 GOPATH
GOPATH 是工作目錄,用于存放 Go 代碼、包和依賴等:
- 創(chuàng)建 GOPATH 目錄,例如:
mkdir -p $HOME/go - 設(shè)置環(huán)境變量:
- Windows: 添加
GOPATH系統(tǒng)環(huán)境變量,值為你創(chuàng)建的目錄路徑 - macOS/Linux: 在
~/.profile或~/.bashrc中添加export GOPATH=$HOME/go
- Windows: 添加
- GOPATH 目錄結(jié)構(gòu):
src: 源代碼pkg: 包文件bin: 可執(zhí)行文件
2. 語法與包管理
Go 基礎(chǔ)語法
查看 hello.go 文件了解 Go 的基本語法,包括:
- 包聲明與導(dǎo)入
- 變量聲明與使用
- 基本數(shù)據(jù)類型
- 控制流(條件語句、循環(huán))
- 函數(shù)定義與調(diào)用
- 切片與數(shù)組操作
運(yùn)行 Go 程序
go run hello.go
構(gòu)建 Go 程序
go build hello.go
./hello # 運(yùn)行編譯后的可執(zhí)行文件
包管理 (Go Modules)
從 Go 1.11 開始,Go 引入了 Go Modules 作為官方的依賴管理解決方案:
-
初始化一個(gè)新模塊:
go mod init example.com/myproject -
添加依賴:
go get github.com/some/dependency -
整理和更新依賴:
go mod tidy -
查看所有依賴:
go list -m all
常用標(biāo)準(zhǔn)庫
fmt: 格式化輸入輸出io: 基本 I/O 接口os: 操作系統(tǒng)功能net/http: HTTP 客戶端和服務(wù)器encoding/json: JSON 編解碼time: 時(shí)間相關(guān)功能sync: 同步原語
推薦學(xué)習(xí)資源
擴(kuò)展練習(xí)
- 修改
hello.go添加更多功能 - 創(chuàng)建一個(gè)簡單的 HTTP 服務(wù)器
- 實(shí)現(xiàn)文件讀寫操作
- 使用 Go 實(shí)現(xiàn)一個(gè)簡單的 CLI 工具
Kratos 微服務(wù)框架入門
Kratos 是一個(gè)輕量級(jí)的、模塊化的、可插拔的Go微服務(wù)框架,專注于幫助開發(fā)人員快速構(gòu)建微服務(wù)。本教程將帶你深入了解 Kratos 的核心概念和使用方法。
1. Kratos 核心介紹
Kratos 是嗶哩嗶哩開源的一款Go微服務(wù)框架,具有以下核心特點(diǎn):
1.1 核心理念
- 簡潔:提供了簡潔、統(tǒng)一的接口定義和使用方式
- 模塊化:各個(gè)組件可獨(dú)立使用,也可組合使用
- 可擴(kuò)展:支持各類中間件和插件的擴(kuò)展
- 高性能:追求極致的性能優(yōu)化
1.2 主要特性
- 傳輸層:支持 HTTP 和 gRPC 服務(wù),并提供統(tǒng)一抽象
- 中間件:豐富的內(nèi)置中間件,如日志、指標(biāo)、跟蹤、限流等
- 注冊(cè)發(fā)現(xiàn):支持多種服務(wù)注冊(cè)與發(fā)現(xiàn)機(jī)制
- 配置管理:靈活的配置加載和動(dòng)態(tài)配置
- 錯(cuò)誤處理:統(tǒng)一的錯(cuò)誤處理和錯(cuò)誤碼管理
- API定義:使用 Protocol Buffers 作為 API 定義語言
- 依賴注入:使用 Wire 進(jìn)行依賴管理和注入
1.3 設(shè)計(jì)架構(gòu)
Kratos 采用領(lǐng)域驅(qū)動(dòng)設(shè)計(jì) (DDD) 的六邊形架構(gòu),將應(yīng)用分為以下層次:
- API層:定義服務(wù)接口,通常使用Proto文件
- Service層:處理服務(wù)業(yè)務(wù)邏輯的實(shí)現(xiàn)
- Biz層:核心業(yè)務(wù)邏輯和領(lǐng)域模型
- Data層:數(shù)據(jù)訪問層,負(fù)責(zé)與持久化存儲(chǔ)交互
- Server層:傳輸層,提供HTTP/gRPC服務(wù)
2. 項(xiàng)目初始化方法
Kratos 提供了完善的項(xiàng)目初始化流程,幫助開發(fā)者快速創(chuàng)建項(xiàng)目骨架。
2.1 安裝 Kratos 命令行工具
# 安裝最新版本的 Kratos 命令行工具
go install github.com/go-kratos/kratos/cmd/kratos/v2@latest
2.2 創(chuàng)建新項(xiàng)目
# 創(chuàng)建名為 myproject 的新項(xiàng)目
kratos new myproject
# 進(jìn)入項(xiàng)目目錄
cd myproject
2.3 添加 API 定義
# 創(chuàng)建 API 文件
kratos proto add api/myproject/v1/myproject.proto
2.4 生成 API 代碼
在編寫完 proto 文件后,使用 kratos 命令生成相應(yīng)代碼:
# 生成客戶端代碼
kratos proto client api/myproject/v1/myproject.proto
# 生成服務(wù)端代碼
kratos proto server api/myproject/v1/myproject.proto -t internal/service
3. CLI 工具詳解
Kratos CLI 是 Kratos 框架的命令行工具,提供了豐富的功能幫助開發(fā)者提高效率。
3.1 主要命令
| 命令 | 說明 | 用法示例 |
|---|---|---|
new |
創(chuàng)建新項(xiàng)目 | kratos new myproject |
proto |
管理 Proto 文件與代碼生成 | kratos proto add/client/server |
run |
運(yùn)行項(xiàng)目 | kratos run |
build |
構(gòu)建項(xiàng)目 | kratos build |
upgrade |
更新 Kratos 工具 | kratos upgrade |
3.2 Proto 相關(guān)命令
# 添加新的 proto 文件
kratos proto add api/helloworld/v1/greeter.proto
# 生成 client 代碼
kratos proto client api/helloworld/v1/greeter.proto
# 生成 server 代碼
kratos proto server api/helloworld/v1/greeter.proto -t internal/service
# 生成所有代碼
kratos proto all api/helloworld/v1/greeter.proto -t internal/service
3.3 工具依賴
使用 Kratos 相關(guān)功能需要安裝以下組件:
# 安裝 protoc 編譯器依賴
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
go install github.com/go-kratos/kratos/cmd/protoc-gen-go-http/v2@latest
go install github.com/go-kratos/kratos/cmd/protoc-gen-go-errors/v2@latest
4. 依賴注入
Kratos 使用 Wire 框架進(jìn)行依賴注入,實(shí)現(xiàn)了組件的松耦合和代碼的可測(cè)試性。
4.1 Wire 基礎(chǔ)
Wire 是 Google 開發(fā)的編譯時(shí)依賴注入工具,通過代碼生成而非反射實(shí)現(xiàn)依賴注入。
4.2 Provider 定義
在 Kratos 中,各個(gè)組件通過 Provider 函數(shù)提供實(shí)例:
// data層 provider
func NewData(conf *conf.Data, logger log.Logger) (*Data, func(), error) {
// 實(shí)例化數(shù)據(jù)層
cleanup := func() {
// 清理資源
}
return &Data{}, cleanup, nil
}
// biz層 provider
func NewGreeterUsecase(repo GreeterRepo, logger log.Logger) *GreeterUsecase {
return &GreeterUsecase{repo: repo}
}
// service層 provider
func NewGreeterService(uc *biz.GreeterUsecase, logger log.Logger) *GreeterService {
return &GreeterService{uc: uc}
}
4.3 Wire 注入點(diǎn)
在 cmd/server/wire.go 中定義依賴注入:
// ProviderSet 是各層的依賴集合
var ProviderSet = wire.NewSet(
data.ProviderSet,
biz.ProviderSet,
service.ProviderSet,
server.ProviderSet,
)
// 應(yīng)用實(shí)例化函數(shù)
func initApp(*conf.Server, *conf.Data, log.Logger) (*kratos.App, error) {
panic(wire.Build(ProviderSet, newApp))
}
4.4 生成注入代碼
# 生成依賴注入代碼
cd cmd/server
wire
5. 項(xiàng)目結(jié)構(gòu)詳解
Kratos 項(xiàng)目結(jié)構(gòu)遵循 DDD 六邊形架構(gòu),組織清晰。
5.1 標(biāo)準(zhǔn)目錄結(jié)構(gòu)
├── api # API 定義目錄 (protobuf)
│ └── helloworld
│ └── v1
│ └── greeter.proto
├── cmd # 應(yīng)用程序入口
│ └── server
│ ├── main.go
│ ├── wire.go # 依賴注入
│ └── wire_gen.go # 自動(dòng)生成的依賴注入代碼
├── configs # 配置文件目錄
│ └── config.yaml
├── internal # 私有應(yīng)用代碼
│ ├── biz # 業(yè)務(wù)邏輯層 (領(lǐng)域模型)
│ │ ├── biz.go
│ │ └── greeter.go
│ ├── conf # 配置處理代碼
│ │ ├── conf.proto
│ │ └── conf.pb.go
│ ├── data # 數(shù)據(jù)訪問層 (持久化)
│ │ ├── data.go
│ │ └── greeter.go
│ ├── server # 傳輸層(HTTP/gRPC)
│ │ ├── server.go
│ │ ├── http.go
│ │ └── grpc.go
│ └── service # 服務(wù)實(shí)現(xiàn)層
│ └── greeter.go
├── third_party # 第三方 proto 文件
└── go.mod
5.2 各目錄職責(zé)
- api: 定義服務(wù) API 接口,使用 Protocol Buffers
- cmd: 程序入口,包含 main 函數(shù)和依賴注入
- configs: 配置文件
- internal: 私有代碼,不對(duì)外暴露
- biz: 核心業(yè)務(wù)邏輯,包含領(lǐng)域模型和業(yè)務(wù)規(guī)則
- data: 數(shù)據(jù)訪問層,實(shí)現(xiàn)數(shù)據(jù)庫操作和緩存
- server: 服務(wù)器定義,包括 HTTP 和 gRPC 服務(wù)器配置
- service: 服務(wù)實(shí)現(xiàn),連接 API 和業(yè)務(wù)邏輯
- third_party: 第三方依賴的 proto 文件
6. 項(xiàng)目運(yùn)行鏈路分析
Kratos 應(yīng)用從啟動(dòng)到處理請(qǐng)求的完整流程。
6.1 啟動(dòng)流程
- 初始化配置:加載 configs 目錄的配置文件
- 依賴注入:通過 Wire 構(gòu)建應(yīng)用依賴關(guān)系
- 創(chuàng)建服務(wù)器:初始化 HTTP/gRPC 服務(wù)器
- 注冊(cè)服務(wù):注冊(cè) API 實(shí)現(xiàn)
- 啟動(dòng)服務(wù):啟動(dòng)服務(wù)監(jiān)聽
// main.go 中的啟動(dòng)流程
func main() {
// 1. 初始化 logger
logger := log.NewStdLogger(os.Stdout)
// 2. 加載配置
c := config.New(config.WithSource(file.NewSource(flagconf)))
if err := c.Load(); err != nil {
panic(err)
}
// 3. 通過依賴注入創(chuàng)建 app 實(shí)例
app, cleanup, err := wireApp(c, logger)
if err != nil {
panic(err)
}
defer cleanup()
// 4. 啟動(dòng)應(yīng)用
if err := app.Run(); err != nil {
panic(err)
}
}
6.2 請(qǐng)求處理流程
HTTP 請(qǐng)求從接收到響應(yīng)的完整流程:
- 接收請(qǐng)求:HTTP/gRPC 服務(wù)器接收請(qǐng)求
- 中間件處理:請(qǐng)求經(jīng)過中間件鏈(日志、跟蹤、限流等)
- 路由匹配:根據(jù)路徑匹配對(duì)應(yīng)處理器
- 參數(shù)解析:解析和驗(yàn)證請(qǐng)求參數(shù)
- 服務(wù)層處理:Service 層實(shí)現(xiàn)請(qǐng)求處理
- 業(yè)務(wù)邏輯:調(diào)用 Biz 層的領(lǐng)域邏輯
- 數(shù)據(jù)訪問:通過 Data 層訪問數(shù)據(jù)庫或緩存
- 響應(yīng)構(gòu)建:構(gòu)建響應(yīng)數(shù)據(jù)
- 中間件后處理:響應(yīng)經(jīng)過中間件鏈
- 返回響應(yīng):返回給客戶端
6.3 HTTP服務(wù)示例
以下是一個(gè)簡化的 HTTP 服務(wù)示例:
import (
"github.com/go-kratos/kratos/v2"
"github.com/go-kratos/kratos/v2/log"
"github.com/go-kratos/kratos/v2/middleware/recovery"
"github.com/go-kratos/kratos/v2/transport/http"
)
func main() {
// 初始化 logger
logger := log.NewStdLogger(os.Stdout)
// 創(chuàng)建 HTTP 服務(wù)器
httpSrv := http.NewServer(
http.Address(":8000"),
http.Middleware(
recovery.Recovery(), // 異常恢復(fù)中間件
),
)
// 注冊(cè)路由
r := httpSrv.Route("/")
r.GET("/hello", func(ctx http.Context) error {
return ctx.String(200, "Hello Kratos!")
})
// 創(chuàng)建 Kratos 應(yīng)用
app := kratos.New(
kratos.Name("example"),
kratos.Server(httpSrv),
kratos.Logger(logger),
)
// 啟動(dòng)應(yīng)用
if err := app.Run(); err != nil {
log.Error(err)
}
}
6.4 完整服務(wù)架構(gòu)
在實(shí)際項(xiàng)目中,請(qǐng)求處理鏈路涉及多個(gè)組件和層次:
客戶端 → 負(fù)載均衡 → HTTP/gRPC服務(wù)器 → 中間件鏈 → 路由 → Service層 → Biz層 → Data層 → 數(shù)據(jù)庫/緩存
↑ ↓
服務(wù)注冊(cè)/發(fā)現(xiàn) ← ← ← ← ← ← ← ← ← ← ← ← ← ← 響應(yīng) ← ← ← ← ← ←
擴(kuò)展閱讀與資源
React 入門教程
React 是由 Facebook 開發(fā)的一個(gè)用于構(gòu)建用戶界面的 JavaScript 庫。React 使開發(fā)人員能夠構(gòu)建快速、可擴(kuò)展的 Web 應(yīng)用程序。
1. 下載與環(huán)境配置
要開始使用 React,您需要一個(gè)現(xiàn)代的 JavaScript 環(huán)境和 Node.js 開發(fā)環(huán)境。
安裝 Node.js 和 pnpm
首先,安裝 Node.js(包含 npm):
- Windows/macOS: 從 Node.js 官網(wǎng) 下載并安裝
- macOS (使用 Homebrew):
brew install node - Linux:
sudo apt install nodejs npm或sudo yum install nodejs npm
驗(yàn)證安裝:
node -v
然后安裝 pnpm (性能更好的包管理器):
# 使用npm安裝pnpm
npm install -g pnpm
# 驗(yàn)證pnpm安裝
pnpm --version
創(chuàng)建新的 React 應(yīng)用
使用 Create React App 工具創(chuàng)建新的 React 應(yīng)用:
# 創(chuàng)建新項(xiàng)目
pnpm create react-app my-react-app
# 進(jìn)入項(xiàng)目目錄
cd my-react-app
# 啟動(dòng)開發(fā)服務(wù)器
pnpm start
或者使用 Vite 創(chuàng)建(更快的啟動(dòng)速度,推薦):
# 使用 Vite 創(chuàng)建 React 項(xiàng)目
pnpm create vite my-react-app --template react
# 進(jìn)入項(xiàng)目目錄
cd my-react-app
# 安裝依賴
pnpm install
# 啟動(dòng)開發(fā)服務(wù)器
pnpm dev
2. React 基本語法與包管理
基本概念
-
組件 (Components):React 應(yīng)用由組件構(gòu)成
- 函數(shù)組件(推薦)
- 類組件
-
JSX:JavaScript 的語法擴(kuò)展,允許在 JS 中編寫類似 HTML 的代碼
-
Props:向組件傳遞數(shù)據(jù)的方式
-
State:組件的內(nèi)部狀態(tài)
-
Hooks:在函數(shù)組件中使用狀態(tài)和其他 React 特性的 API
函數(shù)組件示例
import React from 'react';
function Greeting(props) {
return <h1>你好,{props.name}!</h1>;
}
export default Greeting;
使用 State Hook
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>你點(diǎn)擊了 {count} 次</p>
<button onClick={() => setCount(count + 1)}>
點(diǎn)擊我
</button>
</div>
);
}
使用 Effect Hook
import React, { useState, useEffect } from 'react';
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setSeconds(seconds => seconds + 1);
}, 1000);
return () => clearInterval(interval);
}, []);
return <div>計(jì)時(shí)器:{seconds} 秒</div>;
}
包管理與依賴
React 項(xiàng)目使用 pnpm 管理依賴(pnpm比npm和yarn更快、更高效):
# 安裝依賴
pnpm add react-router-dom
# 安裝開發(fā)依賴
pnpm add -D typescript @types/react
# 更新所有依賴
pnpm update
# 運(yùn)行腳本
pnpm run dev
pnpm的主要優(yōu)勢(shì):
- 磁盤空間高效:pnpm使用內(nèi)容尋址存儲(chǔ)來避免重復(fù)安裝
- 快速安裝:比npm和yarn快2-3倍
- 嚴(yán)格的依賴管理:更好的避免依賴地獄問題
- 支持monorepo:內(nèi)置對(duì)工作空間的支持
常用的包:
- react-router-dom: 路由管理
- axios: HTTP 請(qǐng)求
- zustand 或 redux-toolkit: 狀態(tài)管理
- styled-components 或 emotion: CSS-in-JS 解決方案
- MUI 或 Ant Design: UI 組件庫
本目錄代碼示例說明
本目錄包含兩個(gè)主要文件:
-
App.jsx: 包含三個(gè)示例組件
- 計(jì)數(shù)器:展示基本的狀態(tài)管理
- 計(jì)時(shí)器:展示 useEffect 的使用
- 待辦事項(xiàng)列表:展示更復(fù)雜的狀態(tài)管理
-
App.css: 為組件提供樣式
如何運(yùn)行示例代碼
要運(yùn)行本示例,需要將這些文件集成到一個(gè) React 項(xiàng)目中:
-
創(chuàng)建新的 React 應(yīng)用:
pnpm create vite react-demo --template react cd react-demo pnpm install -
替換
src/App.jsx和src/App.css為本目錄中的文件 -
啟動(dòng)應(yīng)用:
pnpm dev
pnpm 常用命令參考
# 初始化新項(xiàng)目
pnpm init
# 安裝依賴
pnpm add [package]
# 安裝開發(fā)依賴
pnpm add -D [package]
# 全局安裝
pnpm add -g [package]
# 運(yùn)行腳本
pnpm [script]
# 移除依賴
pnpm remove [package]
# 更新依賴
pnpm update
# 查看過時(shí)依賴
pnpm outdated
學(xué)習(xí)資源
練習(xí)建議
- 修改計(jì)數(shù)器組件,添加最大值和最小值限制
- 為待辦事項(xiàng)添加優(yōu)先級(jí)功能
- 添加一個(gè)新的表單組件,練習(xí)表單處理
- 嘗試使用 Context API 在組件之間共享狀態(tài)
Next.js 入門教程
Next.js 是一個(gè)基于 React 的輕量級(jí)框架,用于構(gòu)建靜態(tài)和服務(wù)器渲染的應(yīng)用程序。它提供了豐富的功能,如服務(wù)器端渲染、靜態(tài)網(wǎng)站生成、API 路由、自動(dòng)代碼分割等。本教程基于 Next.js 13+ 的 App Router。
1. 項(xiàng)目目錄與優(yōu)雅實(shí)踐
Next.js 項(xiàng)目結(jié)構(gòu) (App Router)
一個(gè)典型的 Next.js 項(xiàng)目結(jié)構(gòu)如下:
my-nextjs-app/
│
├── app/ # App Router 目錄(基于文件約定的路由)
│ ├── layout.tsx # 根布局組件
│ ├── page.tsx # 首頁 (/)
│ ├── about/ # 關(guān)于頁面路由
│ │ └── page.tsx # 關(guān)于頁面 (/about)
│ ├── blogs/ # 博客路由
│ │ ├── [id]/ # 動(dòng)態(tài)路由
│ │ │ └── page.tsx # 博客文章頁面
│ │ ├── new/ # 創(chuàng)建新博客
│ │ │ └── page.tsx # 創(chuàng)建博客頁面
│ │ └── page.tsx # 博客列表頁面
│ ├── api/ # API 路由
│ │ └── route.ts # API 處理器
│ ├── globals.css # 全局樣式
│ └── error.tsx # 錯(cuò)誤處理頁面
│
├── components/ # React 組件
│ ├── ui/ # UI 組件
│ └── ClientComponent.tsx # 客戶端組件示例
│
├── lib/ # 工具函數(shù)和庫
│ └── utils.ts
│
├── public/ # 靜態(tài)資源
│ ├── favicon.ico
│ └── images/
│
├── .next/ # Next.js 構(gòu)建輸出 (git ignored)
├── node_modules/ # 依賴 (git ignored)
├── package.json # 項(xiàng)目依賴和腳本
├── pnpm-lock.yaml # pnpm 鎖文件
├── next.config.js # Next.js 配置
├── tsconfig.json # TypeScript 配置
└── README.md # 項(xiàng)目說明
Next.js App Router 優(yōu)雅實(shí)踐
-
文件系統(tǒng)路由約定
app/page.tsx→/(首頁)app/about/page.tsx→/about(關(guān)于頁面)app/blogs/[id]/page.tsx→/blogs/:id(動(dòng)態(tài)路由)- 特殊文件:
layout.tsx: 布局組件loading.tsx: 加載狀態(tài)error.tsx: 錯(cuò)誤處理not-found.tsx: 404頁面
-
數(shù)據(jù)獲取方法
- React Server Components 中的直接獲取
generateStaticParams: 靜態(tài)路徑生成revalidatePath/revalidateTag: 按需重新驗(yàn)證- 客戶端數(shù)據(jù)獲取: SWR 或 React Query
-
API 路由
app/api/*/route.ts文件定義 API 端點(diǎn)- 使用
NextResponse進(jìn)行響應(yīng)處理
-
布局系統(tǒng)
- 嵌套布局
- 平行路由和攔截路由
- 模板和分組
-
渲染策略
- 服務(wù)器組件(默認(rèn))
- 客戶端組件 ('use client')
- 流式渲染和部分渲染
2. 快速啟動(dòng)案例前端
安裝 Node.js 和 pnpm
首先,確保你已安裝 Node.js 和 pnpm:
# 安裝 pnpm (如果尚未安裝)
npm install -g pnpm
# 驗(yàn)證安裝
pnpm --version
創(chuàng)建 Next.js 項(xiàng)目
使用 pnpm 創(chuàng)建新的 Next.js 項(xiàng)目:
# 使用 create-next-app 創(chuàng)建TypeScript項(xiàng)目
pnpm create next-app my-nextjs-app --typescript
# 進(jìn)入項(xiàng)目目錄
cd my-nextjs-app
在創(chuàng)建項(xiàng)目過程中,會(huì)提示你選擇一些選項(xiàng)。請(qǐng)確保選擇 "Yes" 當(dāng)詢問是否使用 App Router 時(shí)。
項(xiàng)目結(jié)構(gòu)設(shè)置
默認(rèn)情況下,create-next-app 生成的項(xiàng)目已經(jīng)包含基本結(jié)構(gòu)。您可以根據(jù)需要添加額外的目錄。
創(chuàng)建首頁
首頁是訪問者首先看到的頁面,在 app/page.tsx 文件中創(chuàng)建:
// app/page.tsx
import Link from 'next/link';
export default function Home() {
return (
<div className="container mx-auto px-4 py-8">
<section className="py-12 text-center">
<h1 className="text-4xl font-bold mb-4">歡迎來到我的博客</h1>
<p className="text-lg text-gray-600 mb-8">探索技術(shù)、設(shè)計(jì)和創(chuàng)意的世界</p>
<Link
href="/blog"
className="px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
>
瀏覽博客文章
</Link>
</section>
<section className="py-8">
<h2 className="text-2xl font-bold mb-6 text-center">最新文章</h2>
<div className="grid md:grid-cols-3 gap-6">
<div className="border rounded-lg p-6 hover:shadow-md transition-shadow">
<h3 className="text-xl font-semibold mb-3">Next.js入門指南</h3>
<p className="text-gray-600 mb-4">了解如何使用Next.js構(gòu)建現(xiàn)代Web應(yīng)用</p>
<Link href="/blog/1" className="text-blue-600 hover:underline">
閱讀更多 →
</Link>
</div>
<div className="border rounded-lg p-6 hover:shadow-md transition-shadow">
<h3 className="text-xl font-semibold mb-3">React服務(wù)器組件詳解</h3>
<p className="text-gray-600 mb-4">深入理解React服務(wù)器組件的工作原理</p>
<Link href="/blog/2" className="text-blue-600 hover:underline">
閱讀更多 →
</Link>
</div>
<div className="border rounded-lg p-6 hover:shadow-md transition-shadow">
<h3 className="text-xl font-semibold mb-3">TypeScript與Next.js</h3>
<p className="text-gray-600 mb-4">如何在Next.js項(xiàng)目中充分利用TypeScript</p>
<Link href="/blog/3" className="text-blue-600 hover:underline">
閱讀更多 →
</Link>
</div>
</div>
</section>
<section className="py-8">
<h2 className="text-2xl font-bold mb-6 text-center">關(guān)于客戶端組件</h2>
<div className="border rounded-lg p-6">
<p className="text-gray-700 mb-4">
Next.js的App Router架構(gòu)區(qū)分<strong>服務(wù)器組件</strong>和<strong>客戶端組件</strong>。
默認(rèn)情況下,所有組件都是服務(wù)器組件,在服務(wù)器上渲染并發(fā)送到客戶端。
</p>
<p className="text-gray-700 mb-4">
當(dāng)需要使用瀏覽器API、添加交互性或使用React hooks時(shí),應(yīng)該使用客戶端組件。
通過在文件頂部添加 <code className="bg-gray-100 px-2 py-1 rounded">'use client'</code> 指令來聲明客戶端組件。
</p>
<div className="bg-gray-50 p-4 rounded-lg">
<h3 className="font-semibold mb-2">客戶端組件示例:</h3>
<pre className="bg-gray-800 text-white p-4 rounded overflow-x-auto">
<code>{`'use client'
import { useState, useEffect } from 'react'
export default function ClientComponent() {
const [count, setCount] = useState(0)
return (
<div>
<h3>計(jì)數(shù)器: {count}</h3>
<button onClick={() => setCount(count + 1)}>
增加
</button>
</div>
)
}`}</code>
</pre>
</div>
</div>
</section>
<section className="py-8">
<h2 className="text-2xl font-bold mb-6 text-center">功能演示</h2>
<div className="grid md:grid-cols-2 gap-6">
<div className="border rounded-lg p-6 hover:shadow-md transition-shadow">
<h3 className="text-xl font-semibold mb-3">博客列表</h3>
<p className="text-gray-600 mb-4">查看使用服務(wù)器組件和模擬數(shù)據(jù)實(shí)現(xiàn)的博客列表頁面</p>
<Link href="/blog" className="text-blue-600 hover:underline">
查看示例 →
</Link>
</div>
<div className="border rounded-lg p-6 hover:shadow-md transition-shadow">
<h3 className="text-xl font-semibold mb-3">客戶端組件</h3>
<p className="text-gray-600 mb-4">了解如何在Next.js中使用客戶端組件實(shí)現(xiàn)交互功能</p>
<Link href="/client-example" className="text-blue-600 hover:underline">
查看示例 →
</Link>
</div>
</div>
</section>
</div>
);
}
首頁包含了以下元素:
- 歡迎區(qū)域,包含標(biāo)題和指向博客列表的鏈接
- 最新文章區(qū)域,展示最近的博客文章
創(chuàng)建頁面
在 app 目錄中創(chuàng)建 page.tsx 文件以添加新頁面:
// app/about/page.tsx
export default function AboutPage() {
return (
<div>
<h1>關(guān)于我們</h1>
<p>這是 Next.js 示例項(xiàng)目的關(guān)于頁面。</p>
</div>
)
}
創(chuàng)建布局
使用 layout.tsx 文件創(chuàng)建布局:
// app/layout.tsx
import type { ReactNode } from 'react';
interface RootLayoutProps {
children: ReactNode;
}
export default function RootLayout({ children }: RootLayoutProps) {
return (
<html lang="zh">
<body>
<header>
<nav>
{/* 導(dǎo)航欄組件 */}
</nav>
</header>
<main>{children}</main>
<footer>? {new Date().getFullYear()} 我的 Next.js 應(yīng)用</footer>
</body>
</html>
)
}
創(chuàng)建動(dòng)態(tài)路由
使用方括號(hào)語法創(chuàng)建動(dòng)態(tài)路由:
// app/blogs/[id]/page.tsx
import { notFound } from 'next/navigation';
import Link from 'next/link';
// 模擬博客數(shù)據(jù)
const blogPosts = [
{
id: '1',
title: 'Next.js入門指南',
content: `
<p>Next.js是一個(gè)基于React的強(qiáng)大框架,它提供了許多內(nèi)置功能,使得構(gòu)建現(xiàn)代Web應(yīng)用變得更加簡單。</p>
<h2>主要特性</h2>
<ul>
<li>服務(wù)器端渲染 (SSR)</li>
<li>靜態(tài)站點(diǎn)生成 (SSG)</li>
<li>API路由</li>
<li>文件系統(tǒng)路由</li>
<li>內(nèi)置CSS和Sass支持</li>
<li>代碼分割和打包優(yōu)化</li>
</ul>
<p>使用Next.js,你可以快速開發(fā)出高性能的React應(yīng)用,無需復(fù)雜的配置。</p>
`,
author: {
name: '張三',
avatar: 'https://randomuser.me/api/portraits/men/1.jpg'
},
publishedAt: '2023-05-15',
tags: ['Next.js', 'React', '前端開發(fā)']
},
{
id: '2',
title: 'React服務(wù)器組件詳解',
content: `
<p>React服務(wù)器組件是React的一項(xiàng)新特性,它允許開發(fā)者創(chuàng)建在服務(wù)器上渲染的組件,從而提高性能并減少客戶端JavaScript的體積。</p>
<h2>服務(wù)器組件的優(yōu)勢(shì)</h2>
<ol>
<li>減少客戶端JavaScript包大小</li>
<li>直接訪問服務(wù)器資源(數(shù)據(jù)庫、文件系統(tǒng)等)</li>
<li>自動(dòng)代碼分割</li>
<li>改善首次加載性能</li>
</ol>
<p>在Next.js的App Router中,所有組件默認(rèn)都是服務(wù)器組件,除非你顯式聲明為客戶端組件。</p>
`,
author: {
name: '李四',
avatar: 'https://randomuser.me/api/portraits/women/2.jpg'
},
publishedAt: '2023-06-22',
tags: ['React', '服務(wù)器組件', '性能優(yōu)化']
},
{
id: '3',
title: 'TypeScript與Next.js',
content: `
<p>TypeScript是JavaScript的超集,添加了靜態(tài)類型檢查,在Next.js項(xiàng)目中使用TypeScript可以帶來諸多好處。</p>
<h2>TypeScript的優(yōu)勢(shì)</h2>
<ul>
<li>靜態(tài)類型檢查,減少運(yùn)行時(shí)錯(cuò)誤</li>
<li>更好的IDE支持,包括代碼補(bǔ)全和智能提示</li>
<li>更容易維護(hù)的代碼庫</li>
<li>自文檔化的代碼</li>
</ul>
<h2>在Next.js中使用TypeScript</h2>
<p>Next.js原生支持TypeScript,你可以直接創(chuàng)建.tsx或.ts文件,無需額外配置。</p>
<p>對(duì)于頁面和API路由,你可以使用TypeScript接口來定義props和請(qǐng)求參數(shù)的類型。</p>
`,
author: {
name: '王五',
avatar: 'https://randomuser.me/api/portraits/men/3.jpg'
},
publishedAt: '2023-07-10',
tags: ['TypeScript', 'Next.js', '類型安全']
}
];
// 獲取博客帖子函數(shù)
const getBlogPost = (id: string) => {
return blogPosts.find(post => post.id === id);
};
// 博客詳情頁面組件
export default function BlogPostPage({ params }: { params: { id: string } }) {
const post = getBlogPost(params.id);
// 如果沒有找到文章,返回404
if (!post) {
notFound();
}
return (
<div className="container mx-auto px-4 py-8">
<article className="max-w-3xl mx-auto">
<div className="mb-8">
<Link href="/blog" className="text-blue-600 hover:underline mb-4 inline-block">
← 返回博客列表
</Link>
<h1 className="text-4xl font-bold mb-4">{post.title}</h1>
<div className="flex items-center mb-6">
<img
src={post.author.avatar}
alt={post.author.name}
className="w-10 h-10 rounded-full mr-3"
/>
<div>
<p className="font-medium">{post.author.name}</p>
<p className="text-gray-500 text-sm">發(fā)布于 {post.publishedAt}</p>
</div>
</div>
<div className="flex flex-wrap gap-2 mb-8">
{post.tags.map(tag => (
<span key={tag} className="bg-blue-100 text-blue-800 text-sm px-3 py-1 rounded-full">
{tag}
</span>
))}
</div>
</div>
<div
className="prose prose-lg max-w-none"
dangerouslySetInnerHTML={{ __html: post.content }}
/>
<div className="mt-12 pt-8 border-t border-gray-200">
<h3 className="text-xl font-bold mb-4">分享這篇文章</h3>
<div className="flex space-x-4">
<button className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700">
分享到微信
</button>
<button className="px-4 py-2 bg-blue-400 text-white rounded hover:bg-blue-500">
分享到微博
</button>
</div>
</div>
</article>
</div>
);
}
創(chuàng)建 API 路由
在 app/api 目錄中創(chuàng)建 API 端點(diǎn):
// app/api/hello/route.ts
// app/api/route.ts
import { NextRequest, NextResponse } from 'next/server'
// 模擬用戶數(shù)據(jù)
const users = [
{ id: '1', name: '張三', email: 'zhangsan@example.com' },
{ id: '2', name: '李四', email: 'lisi@example.com' },
{ id: '3', name: '王五', email: 'wangwu@example.com' }
];
export async function GET() {
return NextResponse.json({
success: true,
data: users,
timestamp: new Date().toISOString()
})
}
export async function POST(request: NextRequest) {
try {
const body = await request.json()
// 驗(yàn)證請(qǐng)求數(shù)據(jù)
if (!body.name) {
return NextResponse.json(
{ success: false, error: '名稱不能為空' },
{ status: 400 }
)
}
// 模擬創(chuàng)建新用戶
const newUser = {
id: (users.length + 1).toString(),
name: body.name,
email: body.email || null
}
// 在真實(shí)應(yīng)用中,這里會(huì)將用戶添加到數(shù)據(jù)庫
// 這里只是模擬
return NextResponse.json({
success: true,
data: newUser
}, { status: 201 })
} catch (error) {
return NextResponse.json(
{ success: false, error: '請(qǐng)求處理失敗' },
{ status: 500 }
)
}
}
數(shù)據(jù)獲取
在服務(wù)器組件中進(jìn)行數(shù)據(jù)獲取(默認(rèn)情況下,page.tsx 是服務(wù)器組件):
// app/blog/page.tsx - 服務(wù)器組件
import Link from 'next/link';
import BlogActions from './components/BlogActions';
// 模擬博客數(shù)據(jù)
const blogs = [
{
id: '1',
title: 'Next.js入門指南',
excerpt: '了解如何使用Next.js構(gòu)建現(xiàn)代Web應(yīng)用',
author: {
name: '張三',
avatar: 'https://randomuser.me/api/portraits/men/1.jpg'
},
publishedAt: '2023-05-15',
tags: ['Next.js', 'React', '前端開發(fā)']
},
{
id: '2',
title: 'React服務(wù)器組件詳解',
excerpt: '深入理解React服務(wù)器組件的工作原理',
author: {
name: '李四',
avatar: 'https://randomuser.me/api/portraits/women/2.jpg'
},
publishedAt: '2023-06-22',
tags: ['React', '服務(wù)器組件', '性能優(yōu)化']
},
{
id: '3',
title: 'TypeScript與Next.js',
excerpt: '如何在Next.js項(xiàng)目中充分利用TypeScript',
author: {
name: '王五',
avatar: 'https://randomuser.me/api/portraits/men/3.jpg'
},
publishedAt: '2023-07-10',
tags: ['TypeScript', 'Next.js', '類型安全']
}
];
// 模擬獲取博客列表函數(shù)
async function getBlogs() {
// 模擬網(wǎng)絡(luò)延遲
await new Promise(resolve => setTimeout(resolve, 500));
return blogs;
}
export default async function BlogsPage() {
// 獲取博客數(shù)據(jù)
const blogList = await getBlogs();
return (
<div className="container mx-auto px-4 py-8">
<div className="flex justify-between items-center mb-8">
<h1 className="text-3xl font-bold">博客列表</h1>
<Link
href="/blog/new"
className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition"
>
創(chuàng)建新博客
</Link>
</div>
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
{blogList.map(blog => (
<div key={blog.id} className="border rounded-lg overflow-hidden hover:shadow-md transition">
<div className="p-6">
<h2 className="text-xl font-bold mb-3">{blog.title}</h2>
<p className="text-gray-600 mb-4">{blog.excerpt}</p>
<div className="flex flex-wrap gap-2 mb-4">
{blog.tags.map(tag => (
<span
key={tag}
className="bg-blue-100 text-blue-800 text-xs px-2 py-1 rounded"
>
{tag}
</span>
))}
</div>
<div className="flex items-center text-sm text-gray-500 mb-4">
<img
src={blog.author.avatar}
alt={blog.author.name}
className="w-6 h-6 rounded-full mr-2"
/>
<span>{blog.author.name}</span>
<span className="mx-2">?</span>
<span>{new Date(blog.publishedAt).toLocaleDateString('zh-CN')}</span>
</div>
<div className="flex space-x-2">
<Link
href={`/blog/${blog.id}`}
className="px-3 py-1 bg-blue-500 text-white rounded hover:bg-blue-600 text-sm"
>
查看全文
</Link>
<Link
href={`/blog/edit/${blog.id}`}
className="px-3 py-1 bg-green-500 text-white rounded hover:bg-green-600 text-sm"
>
編輯
</Link>
<BlogActions blogId={blog.id} />
</div>
</div>
</div>
))}
</div>
{blogList.length === 0 && (
<div className="text-center py-12">
<p className="text-gray-500 mb-4">暫無博客內(nèi)容</p>
<Link
href="/blog/new"
className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700"
>
創(chuàng)建第一篇博客
</Link>
</div>
)}
<div className="mt-8 text-center">
<Link
href="/"
className="text-blue-600 hover:underline"
>
返回首頁
</Link>
</div>
</div>
);
}
使用客戶端組件進(jìn)行交互:
// blog/components/BlogActions.tsx
'use client';
interface BlogActionsProps {
blogId: string;
}
export default function BlogActions({ blogId }: BlogActionsProps) {
const handleDelete = () => {
alert(`刪除功能尚未實(shí)現(xiàn):${blogId}`);
// 這里可以實(shí)現(xiàn)實(shí)際的刪除邏輯
};
return (
<button
className="px-3 py-1 bg-red-500 text-white rounded hover:bg-red-600 text-sm"
onClick={handleDelete}
>
刪除
</button>
);
}
安裝依賴
使用 pnpm 安裝項(xiàng)目依賴:
# 安裝依賴
pnpm add axios swr
# 安裝開發(fā)依賴
pnpm add -D typescript @types/react eslint
運(yùn)行開發(fā)服務(wù)器
pnpm dev
構(gòu)建和部署
# 構(gòu)建應(yīng)用
pnpm build
# 啟動(dòng)生產(chǎn)環(huán)境服務(wù)器
pnpm start
pnpm 優(yōu)勢(shì)
pnpm相比npm和yarn有以下優(yōu)勢(shì):
- 磁盤空間效率:pnpm使用硬鏈接和內(nèi)容尋址存儲(chǔ),減少了重復(fù)的依賴
- 安裝速度快:比npm和yarn快2-3倍
- 更嚴(yán)格的依賴管理:通過使用符號(hào)鏈接確保依賴訪問更安全
- 內(nèi)置monorepo支持:無需額外工具即可管理多包項(xiàng)目
pnpm 常用命令
# 初始化項(xiàng)目
pnpm init
# 安裝所有依賴
pnpm install
# 添加依賴
pnpm add [package]
# 添加開發(fā)依賴
pnpm add -D [package]
# 更新依賴
pnpm update
# 運(yùn)行腳本
pnpm [script]
# 刪除依賴
pnpm remove [package]
Node.js 與 Next.js 的關(guān)系
Node.js 與 Next.js 的基本關(guān)系
Next.js 是構(gòu)建在 Node.js 之上的 React 框架。這種關(guān)系可以從多個(gè)方面理解:
- 運(yùn)行時(shí)環(huán)境:Next.js 使用 Node.js 作為其服務(wù)器端運(yùn)行時(shí)環(huán)境
- 構(gòu)建工具:Next.js 利用 Node.js 生態(tài)系統(tǒng)中的工具(如 webpack、babel)進(jìn)行代碼構(gòu)建和轉(zhuǎn)換
- 包管理:Next.js 項(xiàng)目通過 npm、yarn 或 pnpm 等 Node.js 包管理器管理依賴
- API 實(shí)現(xiàn):Next.js 的服務(wù)器端 API 路由基于 Node.js 的 HTTP 模塊實(shí)現(xiàn)
Next.js 的運(yùn)行時(shí)環(huán)境
Next.js 確實(shí)在 Node.js 環(huán)境中啟動(dòng)了一個(gè)服務(wù)器來接收來自瀏覽器的請(qǐng)求。這個(gè)過程在不同模式下有所不同:
開發(fā)環(huán)境
(pnpm dev)
在開發(fā)模式下:
- Next.js 啟動(dòng)一個(gè) Node.js HTTP 服務(wù)器(默認(rèn)監(jiān)聽 3000 端口)
- 該服務(wù)器具有熱模塊替換(HMR)功能,允許實(shí)時(shí)更新
- 當(dāng)瀏覽器請(qǐng)求到達(dá)時(shí),Next.js 服務(wù)器根據(jù)請(qǐng)求的路徑:
- 對(duì)于頁面請(qǐng)求:執(zhí)行服務(wù)器端渲染(SSR)或提供靜態(tài)生成(SSG)的內(nèi)容
- 對(duì)于 API 請(qǐng)求:執(zhí)行相應(yīng)的 API 路由處理函數(shù)
- 對(duì)于靜態(tài)資源:提供 public 目錄中的文件
- 開發(fā)服務(wù)器還處理源代碼編譯、打包和監(jiān)視文件變化
瀏覽器請(qǐng)求 → Node.js服務(wù)器(Next.js) → 路由解析 → 頁面渲染/API處理 → 響應(yīng)返回
生產(chǎn)環(huán)境
(pnpm build 然后 pnpm start)
在生產(chǎn)模式下:
-
pnpm build預(yù)先構(gòu)建所有可能的頁面和資源- 靜態(tài)生成(SSG)的頁面被預(yù)渲染為HTML
- 服務(wù)器組件被優(yōu)化和序列化
- JavaScript包被優(yōu)化和代碼分割
-
pnpm start啟動(dòng)一個(gè)優(yōu)化的 Node.js 生產(chǎn)服務(wù)器- 這個(gè)服務(wù)器比開發(fā)服務(wù)器輕量得多
- 它主要負(fù)責(zé):
- 提供預(yù)構(gòu)建的靜態(tài)資源
- 處理動(dòng)態(tài)SSR請(qǐng)求
- 執(zhí)行API路由
瀏覽器請(qǐng)求 → Node.js生產(chǎn)服務(wù)器 → 提供預(yù)構(gòu)建資源/動(dòng)態(tài)渲染 → 響應(yīng)返回
渲染模式與Node.js的關(guān)系
-
服務(wù)器端渲染(SSR)
- 每次請(qǐng)求都在 Node.js 環(huán)境中執(zhí)行React組件渲染
- 生成HTML并發(fā)送給瀏覽器
- 適用于需要最新數(shù)據(jù)的頁面
-
靜態(tài)站點(diǎn)生成(SSG)
- 在構(gòu)建時(shí)在 Node.js 環(huán)境中預(yù)渲染HTML
- 請(qǐng)求來臨時(shí)直接提供靜態(tài)HTML
- 適用于內(nèi)容不經(jīng)常變化的頁面
-
增量靜態(tài)再生成(ISR)
- 結(jié)合SSG和SSR的優(yōu)點(diǎn)
- 預(yù)渲染HTML,但在指定間隔后在Node.js環(huán)境中重新生成
-
客戶端渲染
- 初始HTML由服務(wù)器提供
- 后續(xù)渲染和數(shù)據(jù)獲取在瀏覽器中發(fā)生
- 減輕Node.js服務(wù)器負(fù)載
Node.js 環(huán)境的限制
在使用Next.js時(shí),需要注意Node.js環(huán)境的一些特點(diǎn)和限制:
-
服務(wù)器組件 vs 客戶端組件
- 服務(wù)器組件在Node.js環(huán)境中運(yùn)行,可以訪問文件系統(tǒng)、環(huán)境變量等
- 客戶端組件無法訪問Node.js特有的功能和API
-
API路由的Node.js能力
- API路由在Node.js環(huán)境中執(zhí)行,可以使用完整的Node.js功能
- 包括數(shù)據(jù)庫連接、文件系統(tǒng)操作、復(fù)雜計(jì)算等
-
邊緣運(yùn)行時(shí)
- Next.js還支持Edge Runtime(一種輕量級(jí)運(yùn)行時(shí))
- Edge Runtime比Node.js更受限,但部署和冷啟動(dòng)更快
部署架構(gòu)
Next.js應(yīng)用的部署涉及到Node.js服務(wù)器的管理:
-
傳統(tǒng)服務(wù)器
- 部署完整的Node.js服務(wù)器
- 例如在AWS EC2、DigitalOcean等上運(yùn)行
-
無服務(wù)器函數(shù)
- 將Next.js應(yīng)用部署為無服務(wù)器函數(shù)
- 例如AWS Lambda、Vercel等
-
靜態(tài)導(dǎo)出
- 完全靜態(tài)導(dǎo)出,不需要Node.js服務(wù)器
- 使用
next export命令 - 適用于不需要SSR或API路由的項(xiàng)目
本目錄示例代碼說明
本目錄包含以下示例文件:
-
page.tsx: 一個(gè)簡單的 Next.js 首頁示例,展示了:
- 頁面組件結(jié)構(gòu)
- 使用
next/head管理頭部元素 - 使用
next/link進(jìn)行客戶端導(dǎo)航 - React hooks 在 Next.js 中的使用
-
[id].tsx: 展示動(dòng)態(tài)路由的實(shí)現(xiàn),包括:
- 動(dòng)態(tài)路由參數(shù)獲取
- 靜態(tài)生成 (generateStaticParams)
- 數(shù)據(jù)獲取模式
-
route.ts: API 路由示例,展示了:
- 基于請(qǐng)求方法的處理邏輯
- 響應(yīng)處理
- 錯(cuò)誤處理
注意:這些示例基于 App Router 模式實(shí)現(xiàn)。
App Router 和 Pages Router 的區(qū)別
| 特性 | App Router (app/) | Pages Router (pages/) |
|---|---|---|
| 組件模型 | React Server Components | 客戶端組件 |
| 數(shù)據(jù)獲取 | 組件中的 fetch 函數(shù) | getServerSideProps/getStaticProps |
| 布局 | layout.tsx | _app.tsx 和布局組件 |
| 嵌套布局 | 多個(gè) layout.tsx | 需手動(dòng)實(shí)現(xiàn) |
| 加載狀態(tài) | loading.tsx | 需手動(dòng)實(shí)現(xiàn) |
| 錯(cuò)誤處理 | error.tsx | 需手動(dòng)實(shí)現(xiàn)或使用 Error Boundaries |
| API 路由 | route.ts 處理程序 | pages/api/*.ts |
進(jìn)階資源
- Next.js 官方文檔
- Next.js App Router 文檔
- Next.js 學(xué)習(xí)課程
- pnpm 官方文檔
- Vercel 平臺(tái)(Next.js 的創(chuàng)建者提供的托管服務(wù))
- Next.js GitHub 倉庫
練習(xí)建議
- 創(chuàng)建一個(gè)包含多個(gè)頁面的 Next.js 應(yīng)用(使用 App Router)
- 實(shí)現(xiàn)動(dòng)態(tài)路由和數(shù)據(jù)獲取
- 添加多級(jí)嵌套布局
- 創(chuàng)建 API 路由
- 實(shí)現(xiàn)錯(cuò)誤處理和加載狀態(tài)
- 將項(xiàng)目部署到 Vercel 或其他托管平臺(tái)
容器知識(shí)入門教程
容器技術(shù)是現(xiàn)代應(yīng)用開發(fā)和部署的基石,本教程將介紹 Docker 容器的基礎(chǔ)知識(shí)。
Docker 背景介紹
什么是 Docker
Docker 是一個(gè)開源的應(yīng)用容器引擎,讓開發(fā)者可以打包他們的應(yīng)用以及依賴包到一個(gè)可移植的容器中,然后發(fā)布到任何流行的 Linux 或 Windows 操作系統(tǒng)的機(jī)器上。Docker 使用了 Linux 內(nèi)核的多種功能(如 Namespaces、Cgroups)來創(chuàng)建獨(dú)立的容器。
Docker 的發(fā)展歷史
- 2013年:Docker 由 dotCloud 公司(后更名為 Docker Inc.)推出,最初是 dotCloud 平臺(tái)的內(nèi)部項(xiàng)目
- 2014年:Docker 1.0 發(fā)布,正式進(jìn)入生產(chǎn)環(huán)境
- 2015年:Docker Compose、Docker Swarm 和 Docker Machine 等工具發(fā)布,生態(tài)系統(tǒng)開始繁榮
- 2016年:引入內(nèi)置的編排功能
- 2017年:集成 Kubernetes 支持
- 至今:持續(xù)迭代發(fā)展,成為容器化技術(shù)的事實(shí)標(biāo)準(zhǔn)
為什么需要 Docker
在 Docker 出現(xiàn)之前,開發(fā)者面臨以下問題:
- 環(huán)境不一致:開發(fā)、測(cè)試、生產(chǎn)環(huán)境的差異導(dǎo)致"在我電腦上能運(yùn)行"的問題
- 部署復(fù)雜:應(yīng)用依賴安裝復(fù)雜,配置繁瑣
- 資源利用率低:傳統(tǒng)虛擬化方案資源占用高,啟動(dòng)慢
- 應(yīng)用隔離困難:不同應(yīng)用之間相互影響
- 擴(kuò)展性差:難以快速擴(kuò)容和縮容
Docker 通過容器化技術(shù)解決了這些問題:
- 一致的環(huán)境:無論在哪里運(yùn)行,容器內(nèi)的環(huán)境都是一樣的
- 輕量級(jí):容器共享主機(jī)系統(tǒng)內(nèi)核,比傳統(tǒng)虛擬機(jī)占用資源少,啟動(dòng)更快
- 隔離:容器之間彼此隔離,不會(huì)相互影響
- 可移植性:構(gòu)建一次,到處運(yùn)行
- 微服務(wù)支持:適合現(xiàn)代微服務(wù)架構(gòu),每個(gè)服務(wù)獨(dú)立容器化
Docker vs 虛擬機(jī)
| 特性 | Docker 容器 | 虛擬機(jī) |
|---|---|---|
| 啟動(dòng)時(shí)間 | 秒級(jí) | 分鐘級(jí) |
| 存儲(chǔ)空間 | MB級(jí) | GB級(jí) |
| 性能 | 接近原生 | 有所損耗 |
| 系統(tǒng)資源 | 共享宿主機(jī)內(nèi)核 | 獨(dú)立內(nèi)核 |
| 隔離性 | 進(jìn)程級(jí)隔離 | 完全隔離 |
| 運(yùn)行密度 | 單機(jī)可運(yùn)行數(shù)十至數(shù)百個(gè)容器 | 單機(jī)通常運(yùn)行數(shù)個(gè)虛擬機(jī) |
1. Docker 安裝
Windows 安裝
- 下載 Docker Desktop for Windows
- 雙擊安裝程序并按照提示完成安裝
- 安裝完成后,Docker Desktop 會(huì)自動(dòng)啟動(dòng)
- 在系統(tǒng)托盤中可以看到 Docker 圖標(biāo),表示 Docker 服務(wù)正在運(yùn)行
macOS 安裝
- 下載 Docker Desktop for Mac
- 將下載的
.dmg文件拖到應(yīng)用程序文件夾 - 啟動(dòng) Docker Desktop 應(yīng)用
- 等待 Docker 初始化完成,頂部狀態(tài)欄會(huì)顯示 Docker 圖標(biāo)
Linux 安裝 (Ubuntu)
# 更新軟件包索引
sudo apt-get update
# 安裝依賴
sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg \
lsb-release
# 添加 Docker 官方 GPG 密鑰
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# 設(shè)置穩(wěn)定版?zhèn)}庫
echo \
"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 安裝 Docker Engine
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
# 將當(dāng)前用戶添加到 docker 組(避免每次都使用 sudo)
sudo usermod -aG docker $USER
# 需要重新登錄使配置生效
驗(yàn)證安裝
# 查看 Docker 版本
docker --version
# 運(yùn)行測(cè)試容器
docker run hello-world
2. 常用 Docker 命令
鏡像相關(guān)命令
# 搜索鏡像
docker search ubuntu
# 拉取鏡像
docker pull ubuntu:latest
# 列出本地鏡像
docker images
# 刪除鏡像
docker rmi ubuntu:latest
# 構(gòu)建鏡像
docker build -t myapp:1.0 .
容器相關(guān)命令
# 創(chuàng)建并啟動(dòng)容器
docker run -d -p 8080:80 --name mywebserver nginx
# 列出所有運(yùn)行中的容器
docker ps
# 列出所有容器(包括已停止的)
docker ps -a
# 停止容器
docker stop mywebserver
# 啟動(dòng)已停止的容器
docker start mywebserver
# 重啟容器
docker restart mywebserver
# 刪除容器
docker rm mywebserver
# 進(jìn)入容器交互式終端
docker exec -it mywebserver bash
# 查看容器日志
docker logs mywebserver
# 查看容器資源使用情況
docker stats mywebserver
Docker Compose 命令
# 啟動(dòng)所有服務(wù)
docker-compose up -d
# 停止所有服務(wù)
docker-compose down
# 查看服務(wù)狀態(tài)
docker-compose ps
# 查看服務(wù)日志
docker-compose logs
# 重建服務(wù)
docker-compose build
網(wǎng)絡(luò)和存儲(chǔ)命令
# 創(chuàng)建網(wǎng)絡(luò)
docker network create mynetwork
# 列出網(wǎng)絡(luò)
docker network ls
# 創(chuàng)建卷
docker volume create mydata
# 列出卷
docker volume ls
示例項(xiàng)目說明
本目錄包含一個(gè)簡單的 Docker 示例項(xiàng)目,包括:
- Dockerfile: 定義如何構(gòu)建應(yīng)用容器鏡像
- docker-compose.yml: 定義多容器應(yīng)用的服務(wù)、網(wǎng)絡(luò)和卷
- app.js: 一個(gè)簡單的 Node.js Express 應(yīng)用
- package.json: Node.js 應(yīng)用依賴定義
如何運(yùn)行示例項(xiàng)目
-
確保已安裝 Docker 和 Docker Compose
-
在此目錄下運(yùn)行:
docker-compose up -d -
訪問應(yīng)用:
- Web 應(yīng)用: http://localhost:3000
- 健康檢查: http://localhost:3000/health
項(xiàng)目文件說明
Dockerfile
這個(gè)文件定義了如何構(gòu)建應(yīng)用容器:
- 使用 Node.js 16 Alpine 作為基礎(chǔ)鏡像
- 設(shè)置工作目錄
- 復(fù)制和安裝依賴
- 配置環(huán)境變量
- 指定啟動(dòng)命令
docker-compose.yml
這個(gè)文件定義了完整的應(yīng)用棧:
- Web 應(yīng)用服務(wù) (使用 Dockerfile 構(gòu)建)
- PostgreSQL 數(shù)據(jù)庫服務(wù)
- Redis 緩存服務(wù)
- 網(wǎng)絡(luò)配置
- 卷配置(持久存儲(chǔ))
app.js
一個(gè)簡單的 Express 服務(wù)器,展示容器環(huán)境信息和健康檢查端點(diǎn)。
Docker 網(wǎng)絡(luò)詳解
Docker 網(wǎng)絡(luò)是容器化環(huán)境中的關(guān)鍵組件,提供了容器間的通信基礎(chǔ)設(shè)施。
Docker 網(wǎng)絡(luò)的主要作用
- 容器間通信:允許不同容器在不暴露端口到主機(jī)的情況下相互通信
- 隔離環(huán)境:可以創(chuàng)建完全隔離的網(wǎng)絡(luò)環(huán)境,提高應(yīng)用安全性
- 服務(wù)發(fā)現(xiàn):容器可以通過容器名稱而非IP地址相互訪問,簡化服務(wù)發(fā)現(xiàn)
- 多主機(jī)連接:使用overlay網(wǎng)絡(luò)可以連接不同主機(jī)上的容器
- 網(wǎng)絡(luò)策略控制:可以精細(xì)控制哪些容器可以相互通信
常用網(wǎng)絡(luò)類型
# 查看可用的網(wǎng)絡(luò)驅(qū)動(dòng)
docker info | grep "Network"
# 創(chuàng)建自定義網(wǎng)絡(luò)
docker network create --driver bridge my-network
# 在創(chuàng)建容器時(shí)連接到指定網(wǎng)絡(luò)
docker run --network=my-network -d --name container1 nginx
# 將已有容器連接到網(wǎng)絡(luò)
docker network connect my-network container2
網(wǎng)絡(luò)驅(qū)動(dòng)類型
- bridge: 默認(rèn)網(wǎng)絡(luò)驅(qū)動(dòng),適用于同一主機(jī)上的容器
- host: 直接使用主機(jī)網(wǎng)絡(luò),移除容器與主機(jī)間的網(wǎng)絡(luò)隔離
- overlay: 用于Docker Swarm環(huán)境中,連接多個(gè)Docker守護(hù)進(jìn)程
- macvlan: 允許容器擁有獨(dú)立的MAC地址,直接連接到物理網(wǎng)絡(luò)
- none: 禁用所有網(wǎng)絡(luò)
Docker 卷詳解
Docker卷提供了容器數(shù)據(jù)的持久化存儲(chǔ)解決方案,解決了容器銷毀后數(shù)據(jù)丟失的問題。
Docker 卷的主要作用
- 數(shù)據(jù)持久化:即使容器被刪除,存儲(chǔ)在卷中的數(shù)據(jù)依然保留
- 數(shù)據(jù)共享:多個(gè)容器可以掛載相同的卷,實(shí)現(xiàn)數(shù)據(jù)共享
- 備份與恢復(fù):簡化數(shù)據(jù)備份和恢復(fù)流程
- 性能優(yōu)化:與容器內(nèi)部存儲(chǔ)相比,卷通常提供更好的I/O性能
- 存儲(chǔ)解耦:將應(yīng)用與數(shù)據(jù)分離,提高系統(tǒng)靈活性和可維護(hù)性
卷的使用方式
# 創(chuàng)建卷
docker volume create my-data
# 查看卷的詳細(xì)信息
docker volume inspect my-data
# 在容器中使用卷
docker run -d --name my-container -v my-data:/app/data nginx
# 使用綁定掛載(掛載主機(jī)目錄)
docker run -d --name my-container -v $(pwd):/app/data nginx
# 備份卷中的數(shù)據(jù)
docker run --rm -v my-data:/source -v $(pwd):/backup alpine tar -czvf /backup/my-data-backup.tar.gz -C /source .
卷的類型
- 命名卷: 由Docker管理的命名存儲(chǔ)空間
- 綁定掛載: 直接映射主機(jī)文件系統(tǒng)的路徑到容器
- tmpfs掛載: 將數(shù)據(jù)存儲(chǔ)在主機(jī)的內(nèi)存中,不寫入文件系統(tǒng)
使用卷時(shí)要考慮權(quán)限、備份策略和數(shù)據(jù)生命周期管理,以確保數(shù)據(jù)安全和可靠性。
Docker 進(jìn)階概念
- Docker 多階段構(gòu)建:優(yōu)化鏡像大小和構(gòu)建過程
- Docker 網(wǎng)絡(luò):bridge、host、overlay 等不同網(wǎng)絡(luò)驅(qū)動(dòng)
- Docker 卷:持久化數(shù)據(jù)存儲(chǔ)
- Docker Swarm:Docker 原生集群和編排工具
- Docker 安全:最佳實(shí)踐和安全配置
- Docker Registry:鏡像倉庫和分發(fā)
相關(guān)資源
練習(xí)建議
- 嘗試為不同語言的應(yīng)用創(chuàng)建 Dockerfile
- 練習(xí)使用 Docker Compose 設(shè)置多容器應(yīng)用
- 探索 Docker 卷和網(wǎng)絡(luò)
- 學(xué)習(xí)如何在生產(chǎn)環(huán)境中安全地部署 Docker 容器
全棧博客案例
代碼倉庫
go-learning:https://github.com/BaiZe1998/go-learning/tree/main/doutok-course/basic-knowledge
本文分為6個(gè)小節(jié),帶你全方位入門 React & Golang 微服務(wù)全棧開發(fā)。
> 1. golang
> 2. kratos
> 3. react
> 4. next.js
> 5. docker
> 6. 博客案例
每一個(gè)小節(jié)均有豐富的代碼案例,倉庫地址如下:
浙公網(wǎng)安備 33010602011771號(hào)