Go Web 编程快速入门 01 - 环境准备与第一个 Web 应用
这第一篇不求复杂,只要跑起来。你能在本机启动一个小小的 HTTP 服务,返回一段文本或 JSON,就算开了个好头。下面的内容重点是环境准备与第一个 Web 应用的编码与运行,过程尽量顺畅,代码有注释,读完即可上手。
1 开始之前
用 Go 写 Web 服务,有两个要点:环境干净,项目结构简单。其它都可以后面慢慢加。
1.1 安装与验证 Go
- 安装:前往
https://go.dev/dl/
下载并安装 Windows 版 Go(建议 1.20+)。 - 验证:打开 PowerShell,运行:
go version
go env GOPATH GOMODCACHE GOBIN
如果你在国内网络环境,为减少下载阻塞,可以设置代理:
go env -w GOPROXY=https://proxy.golang.com.cn,direct
说明:go version
输出版本;go env
看关键变量;GOPROXY
加速依赖下载。
1.2 推荐工具与目录结构
- IDE:VS Code + Go 扩展(自动安装
gopls
,支持跳转、补全、格式化)。 - 目录建议:一个模块一个文件夹,简洁到能看一眼就明白。
示例结构(本文代码用到):
webapp-01/go.modmain.go
2 创建项目与模块
Go 用模块来管理依赖与构建。初始化一次,后面就省心了。
2.1 初始化 go.mod
在你存放示例代码的位置(如 C:\Users\Administrator\Desktop\webapp-01
),打开 PowerShell:
New-Item -ItemType Directory webapp-01 | Out-Null
Set-Location webapp-01
go mod init example.com/webapp-01
说明:go mod init
的模块名可以用你的域名或占位名(示例里用 example.com/...
)。
3 第一个 Web 应用
我们先用最直接的方式启动一个 HTTP 服务,提供两个接口:/hello
和 /healthz
。
3.1 代码:简洁的 HTTP 服务(main.go)
// 文件:main.go
// 目标:启动一个最简 HTTP 服务,具备基本路由与日志
package mainimport ("fmt""log""net/http""os""time"
)// helloHandler 返回问候语,支持通过查询参数自定义名称:/hello?name=Go
func helloHandler(w http.ResponseWriter, r *http.Request) {start := time.Now()// 读取查询参数 name,默认值为 "World"name := r.URL.Query().Get("name")if name == "" {name = "World"}// 设置响应头(内容类型为纯文本,也可改为 application/json)w.Header().Set("Content-Type", "text/plain; charset=utf-8")// 写入响应内容_, _ = fmt.Fprintf(w, "Hello, %s!\n", name)// 简单的请求日志(方法、路径、耗时)log.Printf("%s %s -> %s", r.Method, r.URL.Path, time.Since(start))
}// healthHandler 返回健康检查结果,常用于探活
func healthHandler(w http.ResponseWriter, r *http.Request) {w.Header().Set("Content-Type", "application/json")_, _ = w.Write([]byte(`{"status":"ok"}`))
}func main() {// 端口可通过环境变量 PORT 设置,默认 8080port := os.Getenv("PORT")if port == "" {port = "8080"}mux := http.NewServeMux()mux.HandleFunc("/hello", helloHandler)mux.HandleFunc("/healthz", healthHandler)addr := ":" + portlog.Printf("starting server at http://localhost%s", addr)// 直接用默认的 ListenAndServe 即可跑起来if err := http.ListenAndServe(addr, mux); err != nil {log.Fatalf("server error: %v", err)}
}
运行与测试:
# 编译并运行(任选其一)
go run .
# 或
go build -o webapp.exe; ./webapp.exe# 发起请求(PowerShell)
Invoke-WebRequest -Uri "http://localhost:8080/hello?name=Gopher" -UseBasicParsing
Invoke-WebRequest -Uri "http://localhost:8080/healthz" -UseBasicParsing# 或者用 curl(如已安装)
curl "http://localhost:8080/hello?name=Gopher"
curl "http://localhost:8080/healthz"
4 更稳一点的服务骨架
生产场景会需要:超时、优雅退出。加一点结构,让服务更“抗造”。
4.1 http.Server + 超时 + 优雅退出
// 文件:main.go(增强版骨架)
package mainimport ("context""log""net/http""os""os/signal""syscall""time"
)func main() {mux := http.NewServeMux()mux.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {name := r.URL.Query().Get("name")if name == "" { name = "World" }w.Header().Set("Content-Type", "text/plain; charset=utf-8")_, _ = w.Write([]byte("Hello, " + name + "!\n"))})mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {w.Header().Set("Content-Type", "application/json")_, _ = w.Write([]byte(`{"status":"ok"}`))})port := os.Getenv("PORT")if port == "" { port = "8080" }srv := &http.Server{Addr: ":" + port,Handler: mux,ReadTimeout: 5 * time.Second, // 读取请求的超时WriteTimeout: 10 * time.Second, // 写响应的超时IdleTimeout: 60 * time.Second, // keep-alive 的空闲超时ReadHeaderTimeout: 2 * time.Second, // 读请求头的超时}// 启动服务(协程中运行)go func() {log.Printf("server listening at http://localhost:%s", port)if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {log.Fatalf("listen error: %v", err)}}()// 捕获中断信号,执行优雅退出quit := make(chan os.Signal, 1)signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)<-quitlog.Println("shutting down...")ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)defer cancel()if err := srv.Shutdown(ctx); err != nil {log.Printf("shutdown error: %v", err)}log.Println("server stopped")
}
说明:http.Server
提供更细的超时控制;Shutdown
会等待正在处理的请求结束,避免直接“掐断”。
5 常见问题与排查
5.1 端口占用
- 报错
address already in use
:换个端口(设置PORT=8081
),或关闭占用进程。
5.2 依赖下载慢
- 设置代理:
go env -w GOPROXY=https://proxy.golang.com.cn,direct
。 - 重试:
go clean -modcache
后重新go mod tidy
。
5.3 请求卡住或报超时
- 本文的增强版设置了超时,确认是否被触发;如果是内网请求,检查防火墙或代理。
6 小结与下一步
你已经完成了两步:装好 Go、跑起第一个 Web 服务。别急着加太多功能,先把基本的路由、响应、日志跑顺手。
下一篇将进入主题:net/http
与 Handler
接口的工作方式,为什么一个函数就能变成处理器,以及怎么组织路由更清晰。