Web基础Web工作方式客户端-服务器模型:Web应用基于客户端-服务器架构。客户端(如浏览器)通过HTTP协议向服务器发送请求,服务器响应这些请求。请求与响应:每个Web交互都包含一个从客户端到服务器的请求和从服务器到客户端的响应。使用Go搭建一个简单的Web服务packagema
package main
import (
"fmt"
"net/http"
)
func helloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, World!")
}
func main() {
http.HandleFunc("/", helloHandler)
http.ListenAndServe(":8080", nil)
}
这段代码创建了一个监听8080端口的简单Web服务器,任何访问根路径/的请求都会被重定向到helloHandler函数处理。
基本概念
主要功能
初始化服务器
http.HandleFunc("/", handlerFunc)
http.ListenAndServe(":8080", nil)
处理请求
func handlerFunc(w http.ResponseWriter, r *http.Request) {
// 处理逻辑
}
读取请求参数
go
func handlerFunc(w http.ResponseWriter, r *http.Request) {
param := r.URL.Query().Get("name")
fmt.Fprintf(w, "Hello, %s!", param)
}
设置响应头
go
func handlerFunc(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"message": "Hello"})
}
使用中间件
go
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("Handling request: %s", r.URL.Path)
next.ServeHTTP(w, r)
})
}
package main
import (
"fmt"
"html/template"
"net/http"
)
type FormData struct {
Name string
Email string
}
func formHandler(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {
err := r.ParseForm()
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
name := r.FormValue("name")
email := r.FormValue("email")
fmt.Fprintf(w, "Name: %s\nEmail: %s", name, email)
} else {
tmpl := template.Must(template.ParseFiles("form.html"))
tmpl.Execute(w, FormData{})
}
}
func main() {
http.HandleFunc("/", formHandler)
http.ListenAndServe(":8080", nil)
}
HTML模板 (form.html)
<!DOCTYPE html>
<html>
<head>
<title>Form Example</title>
</head>
<body>
<h1>Submit Form</h1>
<form action="/" method="post">
Name: <input type="text" name="name"><br>
Email: <input type="email" name="email"><br>
<button type="submit">Submit</button>
</form>
</body>
</html>
package main
import (
"fmt"
"html/template"
"net/http"
"strings"
)
type FormData struct {
Name string
Email string
Error string
}
func formHandler(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {
err := r.ParseForm()
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
name := r.FormValue("name")
email := r.FormValue("email")
if strings.TrimSpace(name) == "" || strings.TrimSpace(email) == "" {
data := FormData{Name: name, Email: email, Error: "Please fill in all fields."}
tmpl := template.Must(template.ParseFiles("form.html"))
tmpl.Execute(w, data)
return
}
fmt.Fprintf(w, "Name: %s\nEmail: %s", name, email)
} else {
tmpl := template.Must(template.ParseFiles("form.html"))
tmpl.Execute(w, FormData{})
}
}
func main() {
http.HandleFunc("/", formHandler)
http.ListenAndServe(":8080", nil)
}
HTML模板 (form.html)
<!DOCTYPE html>
<html>
<head>
<title>Form Example</title>
</head>
<body>
<h1>Submit Form</h1>
{{ if .Error }}
<p style="color:red;">{{ .Error }}</p>
{{ end }}
<form action="/" method="post">
Name: <input type="text" name="name" value="{{ .Name }}"><br>
Email: <input type="email" name="email" value="{{ .Email }}"><br>
<button type="submit">Submit</button>
</form>
</body>
</html>
package main
import (
"fmt"
"html/template"
"net/http"
"strings"
)
type FormData struct {
Name string
Email string
Error string
}
func formHandler(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {
err := r.ParseForm()
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
name := r.FormValue("name")
email := r.FormValue("email")
if strings.TrimSpace(name) == "" || strings.TrimSpace(email) == "" {
data := FormData{Name: name, Email: email, Error: "Please fill in all fields."}
tmpl := template.Must(template.ParseFiles("form.html"))
tmpl.Execute(w, data)
return
}
// Escape user input to prevent XSS
name = html.EscapeString(name)
email = html.EscapeString(email)
fmt.Fprintf(w, "Name: %s\nEmail: %s", name, email)
} else {
tmpl := template.Must(template.ParseFiles("form.html"))
tmpl.Execute(w, FormData{})
}
}
func main() {
http.HandleFunc("/", formHandler)
http.ListenAndServe(":8080", nil)
}
package main
import (
"fmt"
"html/template"
"net/http"
"strings"
)
type FormData struct {
Name string
Email string
Error string
Token string
}
func formHandler(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {
err := r.ParseForm()
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
token := r.FormValue("token")
if token != r.FormValue("csrf_token") {
http.Error(w, "Invalid CSRF token", http.StatusBadRequest)
return
}
name := r.FormValue("name")
email := r.FormValue("email")
if strings.TrimSpace(name) == "" || strings.TrimSpace(email) == "" {
data := FormData{Name: name, Email: email, Token: token, Error: "Please fill in all fields."}
tmpl := template.Must(template.ParseFiles("form.html"))
tmpl.Execute(w, data)
return
}
// Escape user input to prevent XSS
name = html.EscapeString(name)
email = html.EscapeString(email)
fmt.Fprintf(w, "Name: %s\nEmail: %s", name, email)
} else {
token := generateToken()
data := FormData{Token: token}
tmpl := template.Must(template.ParseFiles("form.html"))
tmpl.Execute(w, data)
}
}
func generateToken() string {
// Generate a random token here
return "random-token"
}
func main() {
http.HandleFunc("/", formHandler)
http.ListenAndServe(":8080", nil)
}
HTML模板 (form.html)
<!DOCTYPE html>
<html>
<head>
<title>Form Example</title>
</head>
<body>
<h1>Submit Form</h1>
{{ if .Error }}
<p style="color:red;">{{ .Error }}</p>
{{ end }}
<form action="/" method="post">
<input type="hidden" name="csrf_token" value="{{ .Token }}">
Name: <input type="text" name="name" value="{{ .Name }}"><br>
Email: <input type="email" name="email" value="{{ .Email }}"><br>
<button type="submit">Submit</button>
</form>
</body>
</html>
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"path/filepath"
)
func uploadHandler(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {
r.ParseMultipartForm(10 << 20) // 10 MB limit
file, handler, err := r.FormFile("upload")
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
defer file.Close()
tempFile, err := ioutil.TempFile("uploads", "upload-*.png")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer tempFile.Close()
fileBytes, err := ioutil.ReadAll(file)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
tempFile.Write(fileBytes)
fmt.Fprintf(w, "Successfully uploaded %s\n", handler.Filename)
} else {
tmpl := template.Must(template.ParseFiles("upload.html"))
tmpl.Execute(w, nil)
}
}
func main() {
http.HandleFunc("/", uploadHandler)
http.ListenAndServe(":8080", nil)
}
HTML模板 (upload.html)
<!DOCTYPE html>
<html>
<head>
<title>Upload File</title>
</head>
<body>
<h1>Upload File</h1>
<form action="/" method="post" enctype="multipart/form-data">
Select file to upload:
<input type="file" name="upload">
<button type="submit">Upload</button>
</form>
</body>
</html>
基础概念
package main
import (
"database/sql"
"fmt"
"log"
_ "github.com/go-sql-driver/mysql"
)
func main() {
db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/dbname")
if err != nil {
log.Fatal(err)
}
defer db.Close()
err = db.Ping()
if err != nil {
log.Fatal(err)
}
rows, err := db.Query("SELECT id, name FROM users")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var id int
var name string
err := rows.Scan(&id, &name)
if err != nil {
log.Fatal(err)
}
fmt.Println(id, name)
}
err = rows.Err()
if err != nil {
log.Fatal(err)
}
}
package main
import (
"database/sql"
"fmt"
"log"
_ "github.com/go-sql-driver/mysql"
)
func main() {
db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/dbname")
if err != nil {
log.Fatal(err)
}
defer db.Close()
err = db.Ping()
if err != nil {
log.Fatal(err)
}
// 创建表
_, err = db.Exec("CREATE TABLE IF NOT EXISTS users (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255))")
if err != nil {
log.Fatal(err)
}
// 插入数据
_, err = db.Exec("INSERT INTO users (name) VALUES (?)", "Alice")
if err != nil {
log.Fatal(err)
}
// 查询数据
rows, err := db.Query("SELECT id, name FROM users")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var id int
var name string
err := rows.Scan(&id, &name)
if err != nil {
log.Fatal(err)
}
fmt.Println(id, name)
}
err = rows.Err()
if err != nil {
log.Fatal(err)
}
}
package main
import (
"database/sql"
"fmt"
"log"
_ "github.com/mattn/go-sqlite3"
)
func main() {
db, err := sql.Open("sqlite3", "./test.db")
if err != nil {
log.Fatal(err)
}
defer db.Close()
err = db.Ping()
if err != nil {
log.Fatal(err)
}
// 创建表
_, err = db.Exec("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)")
if err != nil {
log.Fatal(err)
}
// 插入数据
_, err = db.Exec("INSERT INTO users (name) VALUES (?)", "Alice")
if err != nil {
log.Fatal(err)
}
// 查询数据
rows, err := db.Query("SELECT id, name FROM users")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var id int
var name string
err := rows.Scan(&id, &name)
if err != nil {
log.Fatal(err)
}
fmt.Println(id, name)
}
err = rows.Err()
if err != nil {
log.Fatal(err)
}
}
package main
import (
"database/sql"
"fmt"
"log"
_ "github.com/lib/pq"
)
func main() {
db, err := sql.Open("postgres", "user=postgres dbname=mydb sslmode=disable password=secret")
if err != nil {
log.Fatal(err)
}
defer db.Close()
err = db.Ping()
if err != nil {
log.Fatal(err)
}
// 创建表
_, err = db.Exec("CREATE TABLE IF NOT EXISTS users (id SERIAL PRIMARY KEY, name TEXT)")
if err != nil {
log.Fatal(err)
}
// 插入数据
_, err = db.Exec("INSERT INTO users (name) VALUES ($1)", "Alice")
if err != nil {
log.Fatal(err)
}
// 查询数据
rows, err := db.Query("SELECT id, name FROM users")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var id int
var name string
err := rows.Scan(&id, &name)
if err != nil {
log.Fatal(err)
}
fmt.Println(id, name)
}
err = rows.Err()
if err != nil {
log.Fatal(err)
}
}
package main
import (
"fmt"
"log"
"os"
"github.com/astaxie/beego/orm"
)
type User struct {
Id int
Name string
}
func init() {
orm.RegisterDriver("mysql", orm.DRMySQL)
orm.RegisterDataBase("default", "mysql", "user:password@tcp(127.0.0.1:3306)/dbname")
orm.RegisterModel(new(User))
}
func main() {
orm.Debug = true
o := orm.NewOrm()
o.Using("default") // 默认使用 default
// 创建表
o.CreateTable(&User{})
// 插入数据
user := User{Name: "Alice"}
id, err := o.Insert(&user)
if err != nil {
log.Fatal(err)
}
fmt.Println("Inserted ID:", id)
// 查询数据
var users []User
_, err = o.QueryTable("users").All(&users)
if err != nil {
log.Fatal(err)
}
for _, u := range users {
fmt.Println(u.Id, u.Name)
}
// 更新数据
user.Name = "Bob"
_, err = o.Update(&user)
if err != nil {
log.Fatal(err)
}
// 删除数据
_, err = o.Delete(&user)
if err != nil {
log.Fatal(err)
}
}
使用MongoDB
package main
import (
"context"
"fmt"
"log"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
func main() {
clientOptions := options.Client().ApplyURI("mongodb://localhost:27017")
client, err := mongo.Connect(context.TODO(), clientOptions)
if err != nil {
log.Fatal(err)
}
defer client.Disconnect(context.TODO())
collection := client.Database("test").Collection("users")
// 插入数据
user := bson.M{"name": "Alice"}
_, err = collection.InsertOne(context.TODO(), user)
if err != nil {
log.Fatal(err)
}
// 查询数据
var result bson.M
err = collection.FindOne(context.TODO(), bson.M{"name": "Alice"}).Decode(&result)
if err != nil {
log.Fatal(err)
}
fmt.Println(result)
// 更新数据
filter := bson.M{"name": "Alice"}
update := bson.M{"$set": bson.M{"name": "Bob"}}
_, err = collection.UpdateOne(context.TODO(), filter, update)
if err != nil {
log.Fatal(err)
}
// 删除数据
_, err = collection.DeleteOne(context.TODO(), bson.M{"name": "Bob"})
if err != nil {
log.Fatal(err)
}
}
Session:
Cookie:
在Go中,可以使用多种方法来管理和使用session。一种常见的方式是使用第三方库,如gorilla/sessions。
使用 gorilla/sessions 安装库:
go get github.com/gorilla/sessions
配置和创建 Session Store:
import (
"github.com/gorilla/sessions"
)
store := sessions.NewCookieStore([]byte("unique-secret-key"))
设置 Session:
session, _ := store.Get(r, "session-name")
session.Values["username"] = "John Doe"
err := session.Save(r, w)
if err != nil {
// 处理错误
}
获取 Session:
session, _ := store.Get(r, "session-name")
username, ok := session.Values["username"].(string)
if !ok {
// 用户名不存在或者类型转换失败
} else {
fmt.Println("Username is", username)
}
Session数据可以存储在不同的地方,包括但不限于:
Session劫持是指攻击者获取合法用户的会话标识符(通常是session ID),从而冒充该用户。为了防止这种情况发生,可以采取以下措施:
使用HTTPS:确保所有通信都是加密的,防止中间人攻击。
设置Cookie属性:
检测并限制IP地址或浏览器指纹的变化:如果用户从不同的位置或设备登录,要求重新验证身份。
基础概念
package main
import (
"bufio"
"fmt"
"log"
"os"
)
func main() {
// 读取文件
file, err := os.Open("input.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
fmt.Println(line)
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
// 写入文件
outFile, err := os.Create("output.txt")
if err != nil {
log.Fatal(err)
}
defer outFile.Close()
writer := bufio.NewWriter(outFile)
_, err = writer.WriteString("Hello, world!\n")
if err != nil {
log.Fatal(err)
}
writer.Flush()
}
基础概念
package main
import (
"encoding/xml"
"fmt"
"log"
"os"
)
type Person struct {
Name string `xml:"name"`
Age int `xml:"age"`
Address struct {
City string `xml:"city"`
State string `xml:"state"`
} `xml:"address"`
}
func main() {
// 解析XML
file, err := os.Open("person.xml")
if err != nil {
log.Fatal(err)
}
defer file.Close()
decoder := xml.NewDecoder(file)
var person Person
err = decoder.Decode(&person)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", person)
// 生成XML
person = Person{
Name: "Alice",
Age: 30,
Address: struct {
City string `xml:"city"`
State string `xml:"state"`
}{
City: "New York",
State: "NY",
},
}
xmlData, err := xml.MarshalIndent(person, "", " ")
if err != nil {
log.Fatal(err)
}
xmlData = append([]byte(xml.Header), xmlData...)
outFile, err := os.Create("output.xml")
if err != nil {
log.Fatal(err)
}
defer outFile.Close()
_, err = outFile.Write(xmlData)
if err != nil {
log.Fatal(err)
}
}
基础概念
package main
import (
"encoding/json"
"fmt"
"log"
"os"
)
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
Address struct {
City string `json:"city"`
State string `json:"state"`
} `json:"address"`
}
func main() {
// 解析JSON
file, err := os.Open("person.json")
if err != nil {
log.Fatal(err)
}
defer file.Close()
decoder := json.NewDecoder(file)
var person Person
err = decoder.Decode(&person)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", person)
// 生成JSON
person = Person{
Name: "Alice",
Age: 30,
Address: struct {
City string `json:"city"`
State string `json:"state"`
}{
City: "New York",
State: "NY",
},
}
jsonData, err := json.MarshalIndent(person, "", " ")
if err != nil {
log.Fatal(err)
}
outFile, err := os.Create("output.json")
if err != nil {
log.Fatal(err)
}
defer outFile.Close()
_, err = outFile.Write(jsonData)
if err != nil {
log.Fatal(err)
}
}
基础概念
package main
import (
"fmt"
"log"
"regexp"
)
func main() {
// 编译正则表达式
re := regexp.MustCompile(`\b[A-Za-z]+\b`)
// 匹配字符串
text := "Hello, world!"
matched := re.MatchString(text)
if matched {
fmt.Println("Matched!")
} else {
fmt.Println("Not matched!")
}
// 查找子串
submatch := re.FindString(text)
fmt.Println("Submatch:", submatch)
// 替换字符串
replaced := re.ReplaceAllString(text, "Hi")
fmt.Println("Replaced:", replaced)
}
基础概念
package main
import (
"html/template"
"log"
"os"
)
type Person struct {
Name string
Age int
}
func main() {
// 创建模板
tmpl := template.Must(template.ParseFiles("template.html"))
// 渲染模板
person := Person{
Name: "Alice",
Age: 30,
}
err := tmpl.Execute(os.Stdout, person)
if err != nil {
log.Fatal(err)
}
}
基础概念
os.Open
打开文件。os.Create
创建文件。os.Remove
删除文件。os.Rename
重命名文件。os.ReadDir
列出目录内容。package main
import (
"fmt"
"log"
"os"
)
func main() {
// 读取文件
file, err := os.Open("input.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
content, err := os.ReadFile("input.txt")
if err != nil {
log.Fatal(err)
}
fmt.Println(string(content))
// 写入文件
err = os.WriteFile("output.txt", []byte("Hello, world!"), 0644)
if err != nil {
log.Fatal(err)
}
// 删除文件
err = os.Remove("output.txt")
if err != nil {
log.Fatal(err)
}
// 重命名文件
err = os.Rename("input.txt", "new-input.txt")
if err != nil {
log.Fatal(err)
}
// 列出目录
files, err := os.ReadDir(".")
if err != nil {
log.Fatal(err)
}
for _, file := range files {
fmt.Println(file.Name())
}
}
基础概念
package main
import (
"fmt"
"strings"
)
func main() {
// 拼接字符串
str1 := "Hello"
str2 := "world"
result := str1 + " " + str2
fmt.Println(result)
// 分割字符串
text := "Hello, world!"
parts := strings.Split(text, ",")
fmt.Println(parts)
// 替换字符串
replaced := strings.ReplaceAll(text, "world", "there")
fmt.Println(replaced)
// 格式化字符串
formatted := fmt.Sprintf("Name: %s, Age: %d", "Alice", 30)
fmt.Println(formatted)
}
基础概念
示例代码 使用net库创建一个简单的TCP服务器和客户端:
服务器端:
package main
import (
"bufio"
"fmt"
"net"
"os"
)
func handleConnection(conn net.Conn) {
defer conn.Close()
scanner := bufio.NewScanner(conn)
for scanner.Scan() {
line := scanner.Text()
fmt.Fprintf(conn, "Echo: %s\n", line)
}
}
func main() {
listener, err := net.Listen("tcp", ":8080")
if err != nil {
fmt.Println("Error listening:", err)
os.Exit(1)
}
defer listener.Close()
for {
conn, err := listener.Accept()
if err != nil {
fmt.Println("Error accepting:", err)
continue
}
go handleConnection(conn)
}
}
客户端:
package main
import (
"bufio"
"fmt"
"net"
"os"
)
func main() {
conn, err := net.Dial("tcp", "localhost:8080")
if err != nil {
fmt.Println("Error connecting:", err)
os.Exit(1)
}
defer conn.Close()
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
line := scanner.Text()
fmt.Fprintf(conn, "%s\n", line)
}
}
基础概念
示例代码
使用gorilla/websocket
库创建一个简单的WebSocket服务器和客户端:
安装库:
go get github.com/gorilla/websocket
服务器端:
package main
import (
"fmt"
"log"
"net/http"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{}
func handleWebSocket(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println("Upgrade error:", err)
return
}
defer conn.Close()
for {
_, message, err := conn.ReadMessage()
if err != nil {
log.Println("Read error:", err)
break
}
log.Printf("Received: %s", message)
err = conn.WriteMessage(websocket.TextMessage, message)
if err != nil {
log.Println("Write error:", err)
break
}
}
}
func main() {
http.HandleFunc("/ws", handleWebSocket)
log.Fatal(http.ListenAndServe(":8080", nil))
}
客户端:
<!DOCTYPE html>
<html>
<head>
<title>WebSocket Client</title>
<script>
var ws = new WebSocket('ws://localhost:8080/ws');
ws.onopen = function(event) {
console.log('WebSocket connected');
};
ws.onmessage = function(event) {
console.log('Received:', event.data);
};
ws.onclose = function(event) {
console.log('WebSocket closed');
};
function sendMessage() {
var message = document.getElementById('message').value;
ws.send(message);
}
</script>
</head>
<body>
<input type="text" id="message">
<button onclick="sendMessage()">Send</button>
</body>
</html>
基础概念
示例代码 使用gin库创建一个简单的RESTful API:
安装库:
go get github.com/gin-gonic/gin
API代码:
package main
import (
"github.com/gin-gonic/gin"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
var users = []User{
{ID: 1, Name: "Alice"},
{ID: 2, Name: "Bob"},
}
func main() {
router := gin.Default()
api := router.Group("/api")
{
api.GET("/users", getUsers)
api.GET("/users/:id", getUserByID)
api.POST("/users", createUser)
api.PUT("/users/:id", updateUser)
api.DELETE("/users/:id", deleteUser)
}
router.Run(":8080")
}
func getUsers(c *gin.Context) {
c.JSON(200, users)
}
func getUserByID(c *gin.Context) {
id := c.Param("id")
userID, err := strconv.Atoi(id)
if err != nil {
c.JSON(400, gin.H{"error": "Invalid user ID"})
return
}
for _, user := range users {
if user.ID == userID {
c.JSON(200, user)
return
}
}
c.JSON(404, gin.H{"error": "User not found"})
}
func createUser(c *gin.Context) {
var user User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
users = append(users, user)
c.JSON(201, user)
}
func updateUser(c *gin.Context) {
id := c.Param("id")
userID, err := strconv.Atoi(id)
if err != nil {
c.JSON(400, gin.H{"error": "Invalid user ID"})
return
}
var updatedUser User
if err := c.ShouldBindJSON(&updatedUser); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
for i, user := range users {
if user.ID == userID {
users[i] = updatedUser
c.JSON(200, updatedUser)
return
}
}
c.JSON(404, gin.H{"error": "User not found"})
}
func deleteUser(c *gin.Context) {
id := c.Param("id")
userID, err := strconv.Atoi(id)
if err != nil {
c.JSON(400, gin.H{"error": "Invalid user ID"})
return
}
filteredUsers := make([]User, 0)
for _, user := range users {
if user.ID != userID {
filteredUsers = append(filteredUsers, user)
}
}
users = filteredUsers
c.JSON(200, gin.H{"message": "User deleted"})
}
基础概念
示例代码 使用gRPC创建一个简单的RPC服务:
安装库:
go get google.golang.org/grpc
定义服务接口:
syntax = "proto3";
service CalculatorService {
rpc Add (AddRequest) returns (AddResponse) {}
}
message AddRequest {
int32 a = 1;
int32 b = 2;
}
message AddResponse {
int32 result = 1;
}
生成代码:
protoc --go_out=. --go-grpc_out=. calculator.proto
服务端代码:
package main
import (
"context"
"log"
"net"
calculatorpb "path/to/calculatorpb"
"google.golang.org/grpc"
)
type server struct{}
func (s *server) Add(ctx context.Context, req *calculatorpb.AddRequest) (*calculatorpb.AddResponse, error) {
result := req.A + req.B
return &calculatorpb.AddResponse{Result: result}, nil
}
func main() {
lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalf("Failed to listen: %v", err)
}
grpcServer := grpc.NewServer()
calculatorpb.RegisterCalculatorServiceServer(grpcServer, &server{})
log.Printf("Starting gRPC server at %s", lis.Addr())
if err := grpcServer.Serve(lis); err != nil {
log.Fatalf("Failed to serve: %v", err)
}
}
示例代码
使用Go语言的CSRF保护
package main
import (
"fmt"
"net/http"
"time"
"github.com/gorilla/csrf"
"github.com/gorilla/mux"
)
func main() {
r := mux.NewRouter()
csrfMiddleware := csrf.Protect([]byte("my_secret_key"), csrf.Secure(false))
r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
token := csrf.Token(r)
fmt.Fprintf(w, "<form action=\"/submit\" method=\"post\">")
fmt.Fprintf(w, "<input type=\"hidden\" name=\"%[1]s\" value=\"%[2]s\"/>", csrf.TokenKey, token)
fmt.Fprintf(w, "<input type=\"text\" name=\"data\"/>")
fmt.Fprintf(w, "<input type=\"submit\" value=\"Submit\"/>")
fmt.Fprintf(w, "</form>")
})
r.HandleFunc("/submit", csrfMiddleware, func(w http.ResponseWriter, r *http.Request) {
data := r.FormValue("data")
fmt.Fprintf(w, "Data submitted: %s", data)
})
http.ListenAndServe(":8080", r)
}
使用Go语言的密码哈希
package main
import (
"fmt"
"log"
"golang.org/x/crypto/bcrypt"
)
func main() {
password := []byte("password123")
// Hash the password
hashedPassword, err := bcrypt.GenerateFromPassword(password, bcrypt.DefaultCost)
if err != nil {
log.Fatalf("Error hashing password: %v", err)
}
fmt.Printf("Hashed Password: %s\n", hashedPassword)
// Check the password
err = bcrypt.CompareHashAndPassword(hashedPassword, password)
if err != nil {
log.Fatalf("Error comparing password: %v", err)
}
fmt.Println("Password is correct.")
}
国际化(i18n)
本地化(l10n)
在Web应用中,通常需要设置一个默认地区,以便在没有明确指定地区的情况下也能正常工作。
示例代码 假设我们使用Go语言来设置默认地区:
package main
import (
"fmt"
"time"
)
func main() {
// 设置默认地区
defaultLocation, _ := time.LoadLocation("Asia/Shanghai")
time.Local = defaultLocation
// 获取当前时间
now := time.Now().In(defaultLocation)
fmt.Println("Current Time:", now.Format("2006-01-02 15:04:05"))
}
在Web应用中,本地化资源主要包括文本、日期、货币等格式化方式。以下是一些常用的本地化资源处理方法。
文本本地化 使用Go语言的i18n包来处理文本本地化:
package main
import (
"fmt"
"strings"
"github.com/nicksnyder/go-i18n/v2/i18n"
)
// 定义翻译资源
var (
bundle = &i18n.Bundle{}
)
func init() {
// 加载翻译文件
enTranslation := map[string]string{
"hello": "Hello, %s!",
"goodbye": "Goodbye, %s!",
}
zhTranslation := map[string]string{
"hello": "你好,%s!",
"goodbye": "再见,%s!",
}
bundle.RegisterUnstructured("en", enTranslation)
bundle.RegisterUnstructured("zh", zhTranslation)
}
func translate(locale string, key string, args ...interface{}) string {
// 创建本地化器
localizer := i18n.NewLocalizer(bundle, locale)
// 翻译文本
msg, err := localizer.Localize(&i18n.LocalizeConfig{
MessageID: key,
TemplateData: args,
})
if err != nil {
return fmt.Sprintf("Translation Error: %v", err)
}
return msg
}
func main() {
// 测试翻译
fmt.Println(translate("en", "hello", "World"))
fmt.Println(translate("zh", "hello", "世界"))
fmt.Println(translate("en", "goodbye", "Alice"))
fmt.Println(translate("zh", "goodbye", "爱丽丝"))
}
日期和时间格式化 使用Go语言的time包来处理日期和时间的格式化:
package main
import (
"fmt"
"time"
)
func formatDateTime(t time.Time, locale string) string {
switch locale {
case "en":
return t.Format("January 2, 2006 3:04 PM")
case "zh":
return t.Format("2006年1月2日 15:04")
default:
return t.Format(time.RFC3339)
}
}
func main() {
now := time.Now()
fmt.Println("English Date:", formatDateTime(now, "en"))
fmt.Println("Chinese Date:", formatDateTime(now, "zh"))
}
货币格式化
使用Go语言的fmt.Sprintf
和strconv
包来处理货币的格式化:
package main
import (
"fmt"
"strconv"
)
func formatCurrency(amount float64, locale string) string {
switch locale {
case "en":
return fmt.Sprintf("$%.2f", amount)
case "zh":
return fmt.Sprintf("¥%.2f", amount)
default:
return fmt.Sprintf("%.2f", amount)
}
}
func main() {
amount := 1234.56
fmt.Println("English Currency:", formatCurrency(amount, "en"))
fmt.Println("Chinese Currency:", formatCurrency(amount, "zh"))
}
在Web应用中,国际化站点通常需要支持多语言版本,并且能够根据用户的地理位置或选择的语言进行切换。
示例代码 使用Go语言和gin框架来实现一个多语言版本的Web站点:
安装库:
go get github.com/gin-gonic/gin
go get github.com/nicksnyder/go-i18n/v2/i18n
定义翻译资源:
package main
import (
"fmt"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"github.com/nicksnyder/go-i18n/v2/i18n"
)
// 定义翻译资源
var (
bundle = &i18n.Bundle{}
)
func init() {
// 加载翻译文件
enTranslation := map[string]string{
"welcome": "Welcome!",
"goodbye": "Goodbye!",
}
zhTranslation := map[string]string{
"welcome": "欢迎!",
"goodbye": "再见!",
}
bundle.RegisterUnstructured("en", enTranslation)
bundle.RegisterUnstructured("zh", zhTranslation)
}
func translate(locale string, key string, args ...interface{}) string {
// 创建本地化器
localizer := i18n.NewLocalizer(bundle, locale)
// 翻译文本
msg, err := localizer.Localize(&i18n.LocalizeConfig{
MessageID: key,
TemplateData: args,
})
if err != nil {
return fmt.Sprintf("Translation Error: %v", err)
}
return msg
}
func main() {
router := gin.Default()
// 设置默认语言
router.DefaultWriter.Header().Set("Content-Language", "en")
// 处理根路径
router.GET("/", func(c *gin.Context) {
locale := c.Query("locale")
if locale == "" {
locale = "en"
}
c.String(http.StatusOK, translate(locale, "welcome"))
})
// 处理其他路径
router.GET("/goodbye", func(c *gin.Context) {
locale := c.Query("locale")
if locale == "" {
locale = "en"
}
c.String(http.StatusOK, translate(locale, "goodbye"))
})
router.Run(":8080")
}
在生产环境中,可以通过环境变量来设置默认地区:
dockerfile
FROM golang:latest
WORKDIR /app
COPY . .
ENV LANG=en_US.UTF-8
ENV LC_ALL=en_US.UTF-8
CMD ["go", "run", "main.go"]
运行容器:
docker build -t myapp .
docker run -p 8080:8080 myapp
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!