GO语言HTTP编程
# GO语言HTTP编程
# 1. HTTP服务器
# 1.1 基本HTTP服务器
package main
import (
"fmt"
"net/http"
)
func helloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, World!")
}
func main() {
http.HandleFunc("/", helloHandler)
fmt.Println("Server starting on :8080")
err := http.ListenAndServe(":8080", nil)
if err != nil {
fmt.Printf("Server failed to start: %v\n", err)
}
}
# 1.2 处理不同的HTTP方法
func userHandler(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case "GET":
fmt.Fprintf(w, "GET: Get user information")
case "POST":
fmt.Fprintf(w, "POST: Create new user")
case "PUT":
fmt.Fprintf(w, "PUT: Update user")
case "DELETE":
fmt.Fprintf(w, "DELETE: Delete user")
default:
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
}
}
func main() {
http.HandleFunc("/user", userHandler)
http.ListenAndServe(":8080", nil)
}
# 1.3 获取请求参数
func queryHandler(w http.ResponseWriter, r *http.Request) {
// 获取查询参数
name := r.URL.Query().Get("name")
age := r.URL.Query().Get("age")
fmt.Fprintf(w, "Name: %s, Age: %s\n", name, age)
}
func formHandler(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {
// 解析表单数据
err := r.ParseForm()
if err != nil {
http.Error(w, "Failed to parse form", http.StatusBadRequest)
return
}
name := r.FormValue("name")
email := r.FormValue("email")
fmt.Fprintf(w, "Name: %s, Email: %s\n", name, email)
} else {
// 返回HTML表单
html := `
<html>
<body>
<form method="POST">
<input type="text" name="name" placeholder="Name"><br>
<input type="email" name="email" placeholder="Email"><br>
<input type="submit" value="Submit">
</form>
</body>
</html>
`
w.Header().Set("Content-Type", "text/html")
fmt.Fprint(w, html)
}
}
# 1.4 处理JSON数据
import (
"encoding/json"
"net/http"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
func jsonHandler(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {
var user User
err := json.NewDecoder(r.Body).Decode(&user)
if err != nil {
http.Error(w, "Invalid JSON", http.StatusBadRequest)
return
}
// 处理用户数据
user.ID = 123 // 模拟分配ID
// 返回JSON响应
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(user)
} else {
// 返回用户列表
users := []User{
{ID: 1, Name: "Alice", Email: "alice@example.com"},
{ID: 2, Name: "Bob", Email: "bob@example.com"},
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(users)
}
}
# 1.5 中间件
func loggingMiddleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
// 调用下一个处理器
next(w, r)
// 记录请求信息
fmt.Printf("%s %s %v\n", r.Method, r.URL.Path, time.Since(start))
}
}
func authMiddleware(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
if token == "" {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
// 验证token(简化示例)
if token != "Bearer valid-token" {
http.Error(w, "Invalid token", http.StatusUnauthorized)
return
}
next(w, r)
}
}
func protectedHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Protected content")
}
func main() {
// 应用中间件
http.HandleFunc("/protected", authMiddleware(loggingMiddleware(protectedHandler)))
http.HandleFunc("/public", loggingMiddleware(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Public content")
}))
http.ListenAndServe(":8080", nil)
}
# 2. HTTP客户端
# 2.1 基本GET请求
package main
import (
"fmt"
"io"
"net/http"
)
func main() {
resp, err := http.Get("https://api.github.com/users/octocat")
if err != nil {
fmt.Printf("Error making request: %v\n", err)
return
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Printf("Error reading response: %v\n", err)
return
}
fmt.Printf("Status: %s\n", resp.Status)
fmt.Printf("Body: %s\n", string(body))
}
# 2.2 POST请求
import (
"bytes"
"encoding/json"
"net/http"
)
type Post struct {
Title string `json:"title"`
Body string `json:"body"`
UserID int `json:"userId"`
}
func main() {
post := Post{
Title: "My Post",
Body: "This is the body of my post",
UserID: 1,
}
jsonData, err := json.Marshal(post)
if err != nil {
fmt.Printf("Error marshaling JSON: %v\n", err)
return
}
resp, err := http.Post(
"https://jsonplaceholder.typicode.com/posts",
"application/json",
bytes.NewBuffer(jsonData),
)
if err != nil {
fmt.Printf("Error making POST request: %v\n", err)
return
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Printf("Response: %s\n", string(body))
}
# 2.3 自定义HTTP客户端
import (
"context"
"net/http"
"time"
)
func main() {
// 创建自定义客户端
client := &http.Client{
Timeout: time.Second * 10,
Transport: &http.Transport{
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 90 * time.Second,
},
}
// 创建请求
req, err := http.NewRequest("GET", "https://api.github.com/users/octocat", nil)
if err != nil {
fmt.Printf("Error creating request: %v\n", err)
return
}
// 添加请求头
req.Header.Set("User-Agent", "MyApp/1.0")
req.Header.Set("Accept", "application/json")
// 设置超时上下文
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
req = req.WithContext(ctx)
// 发送请求
resp, err := client.Do(req)
if err != nil {
fmt.Printf("Error making request: %v\n", err)
return
}
defer resp.Body.Close()
fmt.Printf("Status: %s\n", resp.Status)
}
# 2.4 处理JSON响应
type GitHubUser struct {
Login string `json:"login"`
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
PublicRepos int `json:"public_repos"`
}
func main() {
resp, err := http.Get("https://api.github.com/users/octocat")
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
defer resp.Body.Close()
var user GitHubUser
err = json.NewDecoder(resp.Body).Decode(&user)
if err != nil {
fmt.Printf("Error decoding JSON: %v\n", err)
return
}
fmt.Printf("User: %s (ID: %d)\n", user.Name, user.ID)
fmt.Printf("Public repos: %d\n", user.PublicRepos)
}
# 3. 文件上传
# 3.1 服务器端处理文件上传
func uploadHandler(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {
// 解析多部分表单
err := r.ParseMultipartForm(32 << 20) // 32MB
if err != nil {
http.Error(w, "Failed to parse form", http.StatusBadRequest)
return
}
// 获取上传的文件
file, header, err := r.FormFile("file")
if err != nil {
http.Error(w, "No file uploaded", http.StatusBadRequest)
return
}
defer file.Close()
// 创建目标文件
dst, err := os.Create("./uploads/" + header.Filename)
if err != nil {
http.Error(w, "Failed to create file", http.StatusInternalServerError)
return
}
defer dst.Close()
// 复制文件内容
_, err = io.Copy(dst, file)
if err != nil {
http.Error(w, "Failed to save file", http.StatusInternalServerError)
return
}
fmt.Fprintf(w, "File %s uploaded successfully", header.Filename)
} else {
// 返回上传表单
html := `
<html>
<body>
<form method="POST" enctype="multipart/form-data">
<input type="file" name="file"><br>
<input type="submit" value="Upload">
</form>
</body>
</html>
`
w.Header().Set("Content-Type", "text/html")
fmt.Fprint(w, html)
}
}
# 3.2 客户端上传文件
func uploadFile(filename string, url string) error {
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close()
// 创建multipart writer
var buf bytes.Buffer
writer := multipart.NewWriter(&buf)
// 创建文件字段
part, err := writer.CreateFormFile("file", filename)
if err != nil {
return err
}
// 复制文件内容
_, err = io.Copy(part, file)
if err != nil {
return err
}
writer.Close()
// 发送请求
resp, err := http.Post(url, writer.FormDataContentType(), &buf)
if err != nil {
return err
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Printf("Response: %s\n", string(body))
return nil
}
# 4. 错误处理
# 4.1 HTTP错误处理
func handleHTTPError(resp *http.Response) error {
if resp.StatusCode >= 400 {
body, _ := io.ReadAll(resp.Body)
return fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body))
}
return nil
}
func makeRequest(url string) error {
resp, err := http.Get(url)
if err != nil {
return fmt.Errorf("request failed: %w", err)
}
defer resp.Body.Close()
if err := handleHTTPError(resp); err != nil {
return err
}
// 处理成功响应
return nil
}
# 4.2 重试机制
func makeRequestWithRetry(url string, maxRetries int) error {
var lastErr error
for i := 0; i < maxRetries; i++ {
resp, err := http.Get(url)
if err != nil {
lastErr = err
time.Sleep(time.Second * time.Duration(i+1))
continue
}
defer resp.Body.Close()
if resp.StatusCode == 200 {
return nil
}
lastErr = fmt.Errorf("HTTP %d", resp.StatusCode)
time.Sleep(time.Second * time.Duration(i+1))
}
return fmt.Errorf("failed after %d retries: %w", maxRetries, lastErr)
}
# 5. 最佳实践
# 5.1 设置超时
func createClient() *http.Client {
return &http.Client{
Timeout: 30 * time.Second,
Transport: &http.Transport{
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
},
}
}
# 5.2 使用连接池
var client = &http.Client{
Transport: &http.Transport{
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 90 * time.Second,
},
}
# 5.3 处理大文件
func downloadFile(url, filename string) error {
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
// 使用缓冲复制,避免内存问题
_, err = io.Copy(file, resp.Body)
return err
}
# 5.4 安全考虑
func secureHandler(w http.ResponseWriter, r *http.Request) {
// 设置安全头
w.Header().Set("X-Content-Type-Options", "nosniff")
w.Header().Set("X-Frame-Options", "DENY")
w.Header().Set("X-XSS-Protection", "1; mode=block")
w.Header().Set("Content-Security-Policy", "default-src 'self'")
// 验证内容类型
if r.Header.Get("Content-Type") != "application/json" {
http.Error(w, "Invalid content type", http.StatusBadRequest)
return
}
// 处理请求
fmt.Fprintf(w, "Secure response")
}