将Web框架迁移到Gin

- 安装Gin框架 v1.11.0
- 重构main.go使用Gin路由器
- 更新handlers使用gin.Context
- 重构middleware使用Gin中间件模式
- 更新项目文档(README.md, CLAUDE.md)

项目现已准备好进行数据库集成和前端集成

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
yanlongqi 2025-11-03 11:48:39 +08:00
parent 0361f207db
commit 805c4597af
7 changed files with 219 additions and 64 deletions

View File

@ -4,28 +4,34 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
## Project Overview
AnKao is a Go web application built using the standard library's `net/http` package. The project follows a clean architecture pattern with clear separation of concerns.
AnKao is a Go web application built using the **Gin framework**. The project follows a clean architecture pattern with clear separation of concerns and is designed to support database integration.
## Architecture
### Request Flow
1. HTTP requests arrive at the server running on port 8080
2. Requests pass through the `Logger` middleware (in `internal/middleware/`)
3. The router (`http.NewServeMux`) directs requests to appropriate handlers
4. Handlers (in `internal/handlers/`) process requests and return JSON responses
1. HTTP requests arrive at the Gin server running on port 8080
2. Requests pass through Gin's default middleware (Logger, Recovery) and custom middleware
3. The Gin router matches routes and directs requests to appropriate handlers
4. Handlers (in `internal/handlers/`) process requests using `*gin.Context` and return JSON responses
### Middleware Pattern
Middleware functions wrap the main handler using the standard middleware pattern:
Middleware in Gin uses the `gin.HandlerFunc` pattern:
```go
func Middleware(next http.Handler) http.Handler
func MiddlewareName() gin.HandlerFunc {
return func(c *gin.Context) {
// Pre-processing
c.Next()
// Post-processing
}
}
```
Middleware is applied in [cmd/server/main.go:20](cmd/server/main.go#L20) before starting the server.
Middleware is registered in [main.go:15](main.go#L15) using `r.Use()`.
### Module Structure
- **cmd/server/** - Application entry point, server configuration and routing setup
- **internal/handlers/** - HTTP request handlers, all return JSON responses
- **internal/middleware/** - HTTP middleware chain (currently: logging)
- **internal/models/** - Data models (directory exists but not yet populated)
- **main.go** - Application entry point, server configuration and routing setup
- **internal/handlers/** - HTTP request handlers, all use `*gin.Context` and return JSON responses
- **internal/middleware/** - Gin middleware chain (currently: custom logger)
- **internal/models/** - Data models (directory exists, ready for database models)
- **pkg/config/** - Configuration management (directory exists but not yet populated)
## Common Commands
@ -33,7 +39,7 @@ Middleware is applied in [cmd/server/main.go:20](cmd/server/main.go#L20) before
### Development
```bash
# Run the server
go run cmd/server/main.go
go run main.go
# Install/update dependencies
go mod tidy
@ -48,7 +54,7 @@ go vet ./...
### Building
```bash
# Build binary to bin/server
go build -o bin/server cmd/server/main.go
go build -o bin/server.exe main.go
# Run built binary (Windows)
.\bin\server.exe
@ -67,12 +73,34 @@ go test -cover ./...
# Run tests in a specific package
go test ./internal/handlers/
# Run tests with verbose output
go test -v ./...
```
## Key Implementation Details
- The server listens on port **:8080** (hardcoded in main.go:23)
- All responses are JSON with appropriate Content-Type headers
- Import paths use the module name `ankao` (defined in go.mod)
- When adding new handlers, register them in [cmd/server/main.go](cmd/server/main.go) using `mux.HandleFunc()`
- Middleware wraps the entire mux, so it applies to all routes
- **Framework**: Using Gin v1.11.0
- **Server Port**: :8080 (configured in [main.go:22](main.go#L22))
- **Handler Signature**: All handlers use `func(c *gin.Context)` pattern
- **JSON Response**: Use `c.JSON()` method with `gin.H{}` or structs
- **Import Paths**: Use module name `ankao` (defined in go.mod)
- **Route Registration**: Routes are registered in [main.go](main.go) using `r.GET()`, `r.POST()`, etc.
- **Middleware**: Applied globally with `r.Use()` or per-route with route grouping
## Adding New Features
### Adding a New Handler
1. Create handler function in `internal/handlers/` with signature `func(c *gin.Context)`
2. Use `c.JSON()` to return responses
3. Register route in [main.go](main.go) (e.g., `r.GET("/path", handlers.YourHandler)`)
### Adding Middleware
1. Create middleware in `internal/middleware/` returning `gin.HandlerFunc`
2. Apply globally with `r.Use(middleware.YourMiddleware())` or to route groups
### Database Integration
The project is ready for database integration:
- Add models in `internal/models/`
- Consider using GORM or similar ORM
- Add database initialization in main.go or separate package

View File

@ -1,14 +1,12 @@
# AnKao Web 项目
这是一个使用Go语言构建的Web应用项目。
这是一个使用Go语言和Gin框架构建的Web应用项目。
## 项目结构
```
AnKao/
├── cmd/
│ └── server/ # 主程序入口
│ └── main.go
├── main.go # 主程序入口
├── internal/ # 私有应用代码
│ ├── handlers/ # HTTP请求处理器
│ ├── middleware/ # 中间件
@ -24,7 +22,7 @@ AnKao/
### 运行服务器
```bash
go run cmd/server/main.go
go run main.go
```
服务器将在 `http://localhost:8080` 启动
@ -45,18 +43,29 @@ go mod tidy
### 构建
```bash
go build -o bin/server cmd/server/main.go
go build -o bin/server.exe main.go
```
### 运行编译后的程序
```bash
# Windows
.\bin\server.exe
# Linux/Mac
./bin/server
```
## 特性
- 基于标准库的HTTP服务器
- 日志中间件
- 基于 Gin 框架的高性能 HTTP 服务器
- 自定义日志中间件
- RESTful API 结构
- 健康检查端点
- 支持数据库集成(预留结构)
## 技术栈
- **Go** 1.25.1
- **Gin** v1.11.0 - Web 框架
- 清晰的项目架构,易于扩展

36
go.mod
View File

@ -1,3 +1,39 @@
module ankao
go 1.25.1
require (
github.com/bytedance/gopkg v0.1.3 // indirect
github.com/bytedance/sonic v1.14.2 // indirect
github.com/bytedance/sonic/loader v0.4.0 // indirect
github.com/cloudwego/base64x v0.1.6 // indirect
github.com/gabriel-vasile/mimetype v1.4.11 // indirect
github.com/gin-contrib/sse v1.1.0 // indirect
github.com/gin-gonic/gin v1.11.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.28.0 // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/goccy/go-yaml v1.18.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/quic-go/qpack v0.5.1 // indirect
github.com/quic-go/quic-go v0.55.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.3.1 // indirect
go.uber.org/mock v0.6.0 // indirect
golang.org/x/arch v0.22.0 // indirect
golang.org/x/crypto v0.43.0 // indirect
golang.org/x/mod v0.29.0 // indirect
golang.org/x/net v0.46.0 // indirect
golang.org/x/sync v0.17.0 // indirect
golang.org/x/sys v0.37.0 // indirect
golang.org/x/text v0.30.0 // indirect
golang.org/x/tools v0.38.0 // indirect
google.golang.org/protobuf v1.36.10 // indirect
)

84
go.sum Normal file
View File

@ -0,0 +1,84 @@
github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M=
github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM=
github.com/bytedance/sonic v1.14.2 h1:k1twIoe97C1DtYUo+fZQy865IuHia4PR5RPiuGPPIIE=
github.com/bytedance/sonic v1.14.2/go.mod h1:T80iDELeHiHKSc0C9tubFygiuXoGzrkjKzX2quAx980=
github.com/bytedance/sonic/loader v0.4.0 h1:olZ7lEqcxtZygCK9EKYKADnpQoYkRQxaeY2NYzevs+o=
github.com/bytedance/sonic/loader v0.4.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gabriel-vasile/mimetype v1.4.11 h1:AQvxbp830wPhHTqc1u7nzoLT+ZFxGY7emj5DR5DYFik=
github.com/gabriel-vasile/mimetype v1.4.11/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk=
github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0ktULL6FgHdG688=
github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU=
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
github.com/quic-go/quic-go v0.55.0 h1:zccPQIqYCXDt5NmcEabyYvOnomjs8Tlwl7tISjJh9Mk=
github.com/quic-go/quic-go v0.55.0/go.mod h1:DR51ilwU1uE164KuWXhinFcKWGlEjzys2l8zUl5Ss1U=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY=
github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI=
golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -1,26 +1,22 @@
package handlers
import (
"encoding/json"
"net/http"
"github.com/gin-gonic/gin"
)
// HomeHandler 首页处理器
func HomeHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
response := map[string]string{
func HomeHandler(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "欢迎使用AnKao Web服务",
"version": "1.0.0",
}
json.NewEncoder(w).Encode(response)
})
}
// HealthCheckHandler 健康检查处理器
func HealthCheckHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
response := map[string]string{
func HealthCheckHandler(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"status": "healthy",
}
json.NewEncoder(w).Encode(response)
})
}

View File

@ -2,25 +2,29 @@ package middleware
import (
"log"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
// Logger 日志中间件
func Logger(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
func Logger() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
// 调用下一个处理器
next.ServeHTTP(w, r)
// 处理请求
c.Next()
// 记录请求信息
duration := time.Since(start)
log.Printf(
"%s %s %s %v",
r.Method,
r.RequestURI,
r.RemoteAddr,
time.Since(start),
"[%s] %s %s | %d | %v | %s",
c.Request.Method,
c.Request.RequestURI,
c.ClientIP(),
c.Writer.Status(),
duration,
c.Errors.String(),
)
})
}
}

24
main.go
View File

@ -1,28 +1,26 @@
package main
import (
"log"
"net/http"
"ankao/internal/handlers"
"ankao/internal/middleware"
"github.com/gin-gonic/gin"
)
func main() {
// 创建路由
mux := http.NewServeMux()
// 创建Gin路由器
r := gin.Default()
// 应用自定义中间件
r.Use(middleware.Logger())
// 注册路由
mux.HandleFunc("/", handlers.HomeHandler)
mux.HandleFunc("/api/health", handlers.HealthCheckHandler)
// 应用中间件
handler := middleware.Logger(mux)
r.GET("/", handlers.HomeHandler)
r.GET("/api/health", handlers.HealthCheckHandler)
// 启动服务器
port := ":8080"
log.Printf("服务器启动在端口 %s", port)
if err := http.ListenAndServe(port, handler); err != nil {
log.Fatal("服务器启动失败:", err)
if err := r.Run(port); err != nil {
panic("服务器启动失败: " + err.Error())
}
}