首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Go语言web 开发详细教程,Gin框架使用详解

Go语言web 开发详细教程,Gin框架使用详解

作者头像
程序猿的栖息地
发布2025-07-17 16:46:56
发布2025-07-17 16:46:56
4720
举报
  • go 语言快速创建一个 web server

创建一个 web server

Go 语言里面提供了一个完善的 net/http 包,通过http包可以很方便的就搭建起来一个可以运行的Web服务。同时使用这个包能很便利地对 Web 的路由,静态文件,模版,cookie 等数据进行操作。

一个示例 :
代码语言:javascript
复制
package main

import (
"fmt"
"log"
"net/http"
"strings"
)

func home(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()       // 解析参数,默认是不会解析的
	fmt.Println(r.Form) // 这些信息是输出到服务器端的打印信息
	fmt.Println("path : ", r.URL.Path)
	fmt.Println("scheme : ", r.URL.Scheme)
	fmt.Println(r.Form["url_long"])
for k, v := range r.Form {
		fmt.Println("key:", k)
		fmt.Println("val:", strings.Join(v, ""))
	}
	fmt.Fprintf(w, "网站首页") //这个写入到w的是输出到客户端的
}

func main() {
	http.HandleFunc("/", home)              // 设置访问的路由 如首页
	err := http.ListenAndServe(":800", nil) //设置监听的端口
if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

就是这么方便, 一个 web server 创建好了, 通过访问 : http://localhost:800/ 即可体验 ~

web server 的几个重要概念

代码语言:javascript
复制
Request 用户请求的信息,用来解析用户的请求信息,包括post、get、cookie、url等信息
Response 服务器需要反馈给客户端的信息
Conn 用户的每次请求链接
Handler 处理请求和生成返回信息的处理逻辑

web server 执行流程

代码语言:javascript
复制
1 创建Listen Socket, 监听指定的端口, 等待客户端请求到来。
2 监听并接收客户端的请求, 接下来通过Client Socket与客户端通信。
3 处理客户端的请求, 首先从Client Socket读取HTTP请求的协议头, 如果是POST方法, 还可能要读取客户端提交的数据, 然后交给相应的handler处理请求, handler处理完毕准备好客户端需要的数据, 通过Client Socket写给客户端。

go 语言实现 web server 的关键点

代码语言:javascript
复制
1. 通过 http.ListenAndServe(":800", nil) 监听请求
2. 通过 http.HandleFunc("/", home) 处理请求
3. 通过 http.ResponseWriter() 输出响应结果

web server 工作原理

web server 的几个重要概念

代码语言:javascript
复制
Request 用户请求的信息,用来解析用户的请求信息,包括post、get、cookie、url等信息
Response 服务器需要反馈给客户端的信息
Conn 用户的每次请求链接
Handler 处理请求和生成返回信息的处理逻辑

web server 执行流程

代码语言:javascript
复制
1 创建Listen Socket, 监听指定的端口, 等待客户端请求到来。
2 监听并接收客户端的请求, 接下来通过Client Socket与客户端通信。
3 处理客户端的请求, 首先从Client Socket读取HTTP请求的协议头, 如果是POST方法, 还可能要读取客户端提交的数据, 然后交给相应的handler处理请求, handler处理完毕准备好客户端需要的数据, 通过Client Socket写给客户端。

go 语言实现 web server 的关键点 :

代码语言:javascript
复制
1. 通过 http.ListenAndServe(":800", nil) 监听请求
2. 通过 http.HandleFunc("/", home) 处理请求
3. 通过 http.ResponseWriter() 输出响应结果

handle 详解

golang 是如何处理 web 请求的?

go 语言中一个web 请求会对应创建一个 goroutine 来处理整个请求. Go为了实现高并发和高性能, 使用了goroutines来处理Conn的读写事件, 这样每个请求都能保持独立,相互不会阻塞,可以高效的响应网络事件。

ListenAndServe 函数

ListenAndServe 是创建web 服务器的关键函数 :

代码语言:javascript
复制
第一个参数为 addr 及网络地址, 为空代表 当前主机 80 端口
第二个参数为 http.handler, 如果为 nil 代表使用 DefaultServeMux

handler 为 http.Handler 接口的实现.

创建 web 服务的第二种写法

代码语言:javascript
复制
package main
import (
"net/http"
)
func main() {
	server := http.Server{
		Addr:    ":8080",
		Handler: nil,
	}
	server.ListenAndServe()
}

Handler

Handler 是一个接口, 作为创建web 服务时的第二个参数, 如果为 nil 则为一个 DefaultSeveMax [ 多路复用器 作为路由 ] .

2种模式的路由注册

可以使用 http.HandleFunc 和 http.Handle 注册路由, 2个函数第一个参数都是路径,第2个有所不同 :

http.HandleFunc 的第2个参数为一个复合格式的函数;

http.Handle 的第2个参数为一个具体 handler 的指针地址;

代码语言:javascript
复制
package main

import (
"net/http"
)

func home(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Hello World!"))
}

type aboutHandler struct{}

func (ah *aboutHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("About"))
}

func main() {
	ah := aboutHandler{}
	server := http.Server{
		Addr: ":88",
// 使用 defaultServerMux
		Handler: nil,
	}
	http.HandleFunc("/", home)
	http.Handle("/about", &ah)
	server.ListenAndServe()
}

go 语言内置的 handlers

http.NotFoundHandler

func NotFoundHandler() Handler

返回一个 handler, 响应一个 404;

代码语言:javascript
复制
package main

import "net/http"

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Home"))
	})
	http.Handle("/test", http.NotFoundHandler())
	http.ListenAndServe(":80", nil)
}

http.Redirect

func Redirect(w ResponseWriter, r *Request, url string, code int)

http.Redirect 可以进行重定向 :

代码语言:javascript
复制
package main

import "net/http"

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Home"))
	})
	http.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
		http.Redirect(w, r, "/", http.StatusFound)
	})
	http.ListenAndServe(":80", nil)
}

http.StripPrefix()

func StripPrefix(prefix string, h Handler) Handler

StripPrefix将URL中的前缀中的prefix字符串删除,然后再交给后面的Handler处理,一般是http.FileServer()的返回值。

如果URL不是以prefix开始,或者prefix包含转移字符,最后结果都会返回404,因此要精确匹配URL和prefix;

http.StripPrefix 更像一个中间件 ~

http.TimeoutHandler

func TimeoutHandler(h Handler dt time.Duration, msg string Handler

返回一个 handler,它用来在指定时间内运行传入的 handler。也相当于是一个修饰器

代码语言:javascript
复制
h,将要被修饰的 handler
dt,第一个 handler 允许的处理时间
msg,如果超时,那么就把 msg 返回给请求,表示响应时间过长

示例

代码语言:javascript
复制
package main

import (
"net/http"
"time"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Home"))
	})
	http.Handle("/slow", http.TimeoutHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		time.Sleep(time.Second * 3)
		w.Write([]byte("slow"))
	}), time.Second*2, "Timeout..."))
	http.ListenAndServe(":80", nil)
}

http.FileServer

func FileServer(root FileSystem) Handler

http.FileServer 方法属于标准库 nettp,返回一个使用 FileSystem 接口 root 提供文件访问服务的 HTTP 处理器。可以方便的实现静态文件服务器。

使用时需要用到操作系统的文件系统,所以还需要委托给 :

type Dir string func (d Dir) Open(name string) (File, error)

示例一 基于不同 handler
代码语言:javascript
复制
package main

import (
"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
println(r.URL.Path)
		http.ServeFile(w, r, "html"+r.URL.Path)
	})
	http.ListenAndServe(":80", nil)
}
示例二 整个站点为静态站点
代码语言:javascript
复制
package main

import (
"net/http"
)

func main() {
	http.ListenAndServe(":80", http.FileServer(http.Dir("html")))
}

http 请求相关知识

概述

在 go 语言中 net/http 包用于表述 http 的消息结构,其中 request 用于表述客户端发送的 HTTP 请求消息(请求数据)。

重要的字段 :

代码语言:javascript
复制
URL
Header Body
Form、PostForm、MultipartForm

url 相关

url 数据格式为一个结构体 :

代码语言:javascript
复制
package main

import (
"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// Path 请求路径
println(r.URL.Path)
// RawQuery get 请求参数 ? 后面部分
println(r.URL.RawQuery)
		w.Write([]byte("hi.."))
	})
	http.ListenAndServe(":80", nil)
}

header 相关

header 数据格式为一个 map :

代码语言:javascript
复制
func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, r.Header)
		w.Write([]byte("hi.."))
	})
	http.ListenAndServe(":80", nil)
}
数据示例
代码语言:javascript
复制
[
    Accept:[text/html,application/xhtml+xml,...] 
    Accept-Encoding:[gzip, deflate, br] 
    Accept-Language:[zh-CN,zh;q=0.9] 
    Cache-Control:[max-age=0] 
    Connection:[keep-alive] 
    Sec-Ch-Ua:[" Not A;Brand";v="99", "Chromium";v="102", "Google Chrome";v="102"] 
    Sec-Ch-Ua-Mobile:[?0] 
    Sec-Ch-Ua-Platform:["Windows"] 
    Sec-Fetch-Dest:[document] 
    Sec-Fetch-Mode:[navigate] 
    Sec-Fetch-Site:[none] 
    Sec-Fetch-User:[?1] 
    Upgrade-Insecure-Requests:[1] 
    User-Agent:[Mozilla/5.0 (Windows NT 10.0; Win64...]
]

通过 body 获取请求主体数据

说明 : 可以使用 vscode REST Client 插件 模拟请求

代码语言:javascript
复制
POST  http://localhost/ HTTP/1.1 
Content-Type: application/x-www-form-urlencoded

{
    "name" : "lesscode",
    "age"  : 19
}
接受 body 数据示例
代码语言:javascript
复制
package main

import (
"fmt"
"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		length := r.ContentLength
		body := make([]byte, length)
		r.Body.Read(body)
		fmt.Fprintln(w, string(body))
		w.Write([]byte("hi.."))
	})
	http.ListenAndServe(":80", nil)
}

通过URL Query 接收 get 参数

如 : http://www.***.com/?id=100&name=lesscode

r.URL.RawQuery 会提供实际查询的原始字符串

r.URL.Query(),会提供查询字符串对应的 map[string][]string

代码语言:javascript
复制
package main

import (
"fmt"
"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Index ..."))
		fmt.Fprintln(w, r.URL.Query())
	})
	http.ListenAndServe(":80", nil)
}

通过 form 获取表单及POST 数据

golang 提供 Form、PostForm、MultipartForm 三种方式来获取表单及POST 数据

r.Form

Form 获取的数据保护 POST 数据和 URL 数据

代码语言:javascript
复制
package main

import (
"fmt"
"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Index ..."))
		r.ParseForm()
		fmt.Fprintln(w, r.Form)
	})
	http.ListenAndServe(":80", nil)
}
测试代码
代码语言:javascript
复制
POST  http://localhost/?a=909 HTTP/1.1
Content-Type: application/x-www-form-urlencoded
name=hhhh&age=9

r.PostForm

r.PostForm 只接收 POST 数据

代码语言:javascript
复制
package main

import (
"fmt"
"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Index ..."))
		r.ParseForm()
		fmt.Fprintln(w, r.PostForm)
	})
	http.ListenAndServe(":80", nil)
}

通过 ParseMultipartForm 实现文件上传

go 语言代码

代码语言:javascript
复制
package main

import (
"io"
"log"
"net/http"
"os"
)

func uploadOne(w http.ResponseWriter, r *http.Request) {
//判断请求方式
if r.Method == "POST" {
//设置内存大小
		r.ParseMultipartForm(32 << 20)
		w.Write([]byte("ok."))
//获取上传的第一个文件
		file, header, err := r.FormFile("file")
// 判断文件有效性
if err != nil {
			w.Write([]byte("no..."))
		} else {
defer file.Close()
//创建上传目录
			os.Mkdir("./upload", os.ModePerm)
//创建上传文件
			cur, err := os.Create("./upload/" + header.Filename)
if err != nil {
println(err.Error())
			} else {
defer cur.Close()
//把上传文件数据拷贝到我们新建的文件
				io.Copy(cur, file)
				w.Write([]byte("ok"))
			}
		}
	}
}

func uploadMore(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {
//设置内存大小
		r.ParseMultipartForm(32 << 20)
//获取上传的文件组
		files := r.MultipartForm.File["file"]
len := len(files)
for i := 0; i < len; i++ {
//打开上传文件
			file, err := files[i].Open()
if err != nil {
				log.Fatal(err)
			} else {
defer file.Close()
//创建上传目录
				os.Mkdir("./upload", os.ModePerm)
//创建上传文件
				cur, err := os.Create("./upload/" + files[i].Filename)
if err != nil {
					log.Fatal(err)
				} else {
defer cur.Close()
					io.Copy(cur, file)
				}
			}
		}
	}
}

func main() {
	http.HandleFunc("/uploadMore", uploadMore)
	http.HandleFunc("/uploadOne", uploadOne)
	err := http.ListenAndServe(":9090", nil)
if err != nil {
		log.Fatal(err)
	}
}

前端 html

代码语言:javascript
复制
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <form 
    action="http://127.0.0.1:9090/uploadMore" 
    method="post" 
    enctype="multipart/form-data">
        <div>
            文件:<input type="file" name="file" value="">
        </div>
        <div>
            文件:<input type="file" name="file" value="">
        </div>
        <input type="submit" value="提交">
        <div>提交</div>
    </form>
</body>
</html>

处理静态文件

前面的章节我们讲解了 go web server 相关的知识,我们已经可以对路由进行解析,然后匹配对应的句柄处理路由,实现网站页面的输出。在网站开发过程中静态文件处理也是一个必须的功能,您可以使用 http.Handle 或者 http.HandleFunc 通过静态文件或者静态文件夹解析函数来完成这个功能。

实现代码示例

代码语言:javascript
复制
package main

import (
"log"
"net/http"
)

func home(w http.ResponseWriter, r *http.Request) {
	html := `<html>
	<body>
		<img src="static/demo.png" />
		<div>hello</div>
	</body>
	<html>`
	w.Write([]byte(html))
}

func staticFunc(w http.ResponseWriter, r *http.Request) {
	http.ServeFile(w, r, "./favicon.ico")
}

func main() {
// 首页路由
	http.HandleFunc("/", home)

// 静态文件夹解析
// StripPrefix将URL中的前缀中的prefix字符串删除,
// 然后再交给后面的Handler处理,一般是http.FileServer()的返回值。
// 如果URL不是以prefix开始,或者prefix包含转移字符,最后结果都会返回404,因此要精确匹配URL和prefix

// http.FileServer 函数返回一个Handler,
// 这个 Handler 向h ttp request 提供文件系统内容,一般使用http.Dir(“yourFilePath”)
	http.Handle(
"/static/",
		http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))),
	)

// 单独解析一个静态文件示例
// favicon.ico 文件
	http.HandleFunc("/favicon.ico", staticFunc)

	err := http.ListenAndServe(":800", nil) //设置监听的端口
if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}
  • 模板相关

go 语言模板基础知识

什么模板

Web 模板就是预先设计好的 HTML 页面,它可以被模板引擎反复的使用,来产生 HTML 页面

go 语言的标准库提供了 text/template,html/template两个模板库,大多数 Go 的 Web 框架都使用这些库作为 默认的模板引擎。

go 语言的模板引擎

go 主要使用的是 text/template,HTML 相关的部分使用了 html/template,是个混合体。

模板可以完全无逻辑,但又具有足够的嵌入特性,和大多数模板引擎一样,Go Web 的模板位于无逻辑和嵌入逻辑之间的某个地方。

关于模板

模板必须是可读的文本格式,扩展名任意。对于 Web 应用通常就是 HTML。里面会内嵌一些命令(叫做 action)

text/template 是通用模板引擎,html/template 是HTML 模板引擎 action 位于双层花括号之间:{{.}}这里的,就是一个action,它可以命令模板引擎将其替换成一个值。

示例代码

代码语言:javascript
复制
package main

import (
"net/http"
"text/template"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		template, _ := template.ParseFiles("./templates/index.html")
		template.Execute(w, "hi ...")

	})
	http.ListenAndServe(":80", nil)
}
# 模板代码
代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <span style="color: red;">{{.}}</span>
</body>
</html>

go 语言模板解析与执行

go 语言通过 parseFiles、parseGlob、parse 三个函数来解析模板 :

parseFiles()

func ParseFiles(filenames ...string) (*Template, error)

功能 : 解析指定的一个或者多个模板,返回一个模板结构体,后续可被执行。

parseGlob()

使用模式匹配来解析匹配的模板文件 :

代码语言:javascript
复制
package main

import (
"net/http"
"text/template"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		template, _ := template.ParseGlob("./templates/*.html")
		template.Execute(w, "hi ...")
	})
	http.ListenAndServe(":80", nil)
}

parse()

可以解析字符串模板,上面2个函数最终调用 parse()。

Must() 函数

Must 函数可以包裹一个函数,返回到一个模板的指针 和 一个错误。如果错误不为 nil,那么就 panic。

执行模板

Execute

参数是 ResponseWriter、数据,适用于 : 单模板

ExecuteTemplate

参数是 ResponseWriter、模板名称、数据,适用于 : 多模板

action 相关知识

什么是 action

action 是嵌入 html 模板的命令,位于 {{}} 中间,例如 . 就是一个 action 代表了传入模板的数据。

条件 action

语法 :

代码语言:javascript
复制
{{ if arg }}
    逻辑
{{ end }}

{{ if arg }}
    ......
{{ else }}
    ......
{{ end }}

with 改变 . 的作用范围

语法 :

代码语言:javascript
复制
{{ with "ok" }}
    {{.}}
{{ end }}

包含某个模板

语法 :

代码语言:javascript
复制
{{template 模板名称 .}}

利用 . 传递模板变量

综合示例

main.go

代码语言:javascript
复制
package main

import (
"net/http"
"text/template"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		tmp, _ := template.ParseFiles("./tmpls/index.html", "./tmpls/header.html")
// 定义数据结构体
type Data struct {
			Name string
			List []string
		}
		data := Data{
			Name: "lesscode",
			List: []string{"a", "b", "c"},
		}
// 传入数据
		tmp.Execute(w, data)
	})
	http.ListenAndServe(":80", nil)
}

index.html

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Go</title>
</head>
<body>
    {{template "header.html" .}}
    {{if .Name}}
    <h2>hi.. {{.Name}}</h2>
    {{end}}
    {{ range .List }}
        <div>- {{.}} -</div>
    {{ end }}
    <div>
        {{ with "ok" }}
            {{.}}
        {{ end }}
    </div>
</body>
</html>

header.html

代码语言:javascript
复制
<div style="height:50px; background:red;">
    header..{{.Name}}
</div>

模板自定义函数及管道

自定义函数

您可以在 go 内定义自定义函数并在模板中调用。

使用 template.FuncMap{ } 定义一个函数, 注意函数只能返回一个值,或者一个值 + 错误;然后通过 template.New() 将函数传递到模板调用。

go 示例
代码语言:javascript
复制
package main

import (
"net/http"
"text/template"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// 定义函数
		say := template.FuncMap{"say": func(message string) string {
return "say : " + message
		}}
		t := template.New("index.html")
		t.Funcs(say)
		t, _ = t.ParseFiles("tmpls/index.html")
// 传入数据
		err := t.Execute(w, "test..")
if err != nil {
println(err.Error())
		}
	})
	http.ListenAndServe(":80", nil)
}
模板示例
代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
   <div>hi...{{say .}}</div>
</body>
</html>

管道

管道就是按顺序连接在一起的一串参数和方法。会把管道的输出传递给下一个管道。

语法 : {{ p1 | p2 | p3 }}

代码语言:javascript
复制
<div>{{1.12356 | printf "%.2f"}}</div>

组合模板的应用

组合模板概述

在一般网站开发中,我们经常遇到站点的头部、底部或者左侧菜单是一样的,我们可以使用组合模板来实现这样的功能。

实现组合模板的步骤

1. 定义 layout 布局模板
代码语言:javascript
复制
{{define "layout"}}
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
    <h1>公共头部</h1>
    {{template "body" .}}
    <h1>公共底部</h1>
</body>
</html>
{{end}}
2. 定义内容模板

如 home.html

代码语言:javascript
复制
{{ define "body" }}
<h2>{{.}}</h2>
{{ end }}

和 about.html

代码语言:javascript
复制
{{ define "body" }}
<h2>{{.}}</h2>
<p>关于 ......</p>
{{ end }}
3. 在 handle 中解析并执行对应的模板
代码语言:javascript
复制
package main

import (
"html/template"
"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		t, err := template.ParseFiles("./tmpls/layout.html", "./tmpls/home.html")
if err != nil {
println(err.Error())
return
		}
		t.ExecuteTemplate(w, "layout", "首页")
	})
	http.HandleFunc("/about", func(w http.ResponseWriter, r *http.Request) {
		t, err := template.ParseFiles("./tmpls/layout.html", "./tmpls/about.html")
if err != nil {
println(err.Error())
return
		}
		t.ExecuteTemplate(w, "layout", "关于我们")
	})
	http.ListenAndServe(":80", nil)
}

go 语言模板遍历语法及模板变量定义

go 语言模板遍历语法

html 语法:

代码语言:javascript
复制
{{range $key 或 索引, $遍历元素}}
    HTML 循环元素
{{end}}

go 示例

代码语言:javascript
复制
package main

import (
"net/http"
"text/template"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		template, _ := template.ParseFiles("./templates/index.html")
// 注册多个数据
var data = map[string]any{
"name": "lesscode.work",
"persons": []string{
"小张", "小王", "小李",
			},
		}
		template.Execute(w, data)

	})
	http.ListenAndServe(":80", nil)
}

html 模板文件示例

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
    <ul>
        {{range $idx, $item := .persons}}
        <li>{{$idx}} : {{$item}}</li>
        {{end}}
    </ul>
</body>
</html>

变量传递解决方案

在上面的示例中我们注册了 2个变量 : name 和 persons ,然后我们在 HTML 模板中对 persons 变量进行遍历,在遍历过程中如果我们需要直接使用 name 变量是无法做到的,如 :

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
    <ul>
        {{range $idx, $item := .persons}}
        <li>{{$idx}} : {{$item}} - {{.name}}</li>
        {{end}}
    </ul>
</body>
</html>

原因是 : . ( 英文点 ) 的作用域在遍历过程中被重置,如何解决呢?

定义一个模板变量

定义一个模板变量可以有效解决上面的变量作用域问题,模板变量定于语法 :

代码语言:javascript
复制
{{$变量名称 := .原变量名称}}

示例 :

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
    <ul>
        {{$name := .name}}
        {{range $idx, $item := .persons}}
        <li>{{$idx}} : {{$item}} - {{$name}}</li>
        {{end}}
    </ul>
</body>
</html>
  • Gin web 框架

Gin 快速入门

Gin 介绍

Gin 是 Go 语言写的一个 web 框架,它具有运行速度快,分组的路由器,良好的崩溃捕获和错误处理,非常好的支持中间件和 json。一款值得好好学习并应用的 Web 框架。

官网 : https://gin-gonic.com/zh-cn/docs/

安装 Gin

代码语言:javascript
复制
// 初始化项目 mod
go mod init gotest
// 初始化依赖
go mod tidy
// 安装 Gin
go get -u github.com/gin-gonic/gin

快速开启 Web 服务

在 main.go 文件编写如下代码 :

代码语言:javascript
复制
package main
import "github.com/gin-gonic/gin"
func main() {
// 初始化 Gin 引擎
	r := gin.Default()
// 定义路由
	r.GET("/", func(c *gin.Context) {
		c.JSON(200, gin.H{
"message": "hello",
		})
	})
// 启动 web 服务
	r.Run(":80")
}

快速开启 Web 服务

在 main.go 文件编写如下代码 :

代码语言:javascript
复制
package main
import "github.com/gin-gonic/gin"
func main() {
// 初始化 Gin 引擎
	r := gin.Default()
// 定义路由
	r.GET("/", func(c *gin.Context) {
		c.JSON(200, gin.H{
"message": "hello",
		})
	})
// 启动 web 服务
	r.Run(":80")
}

运行 main.go

代码语言:javascript
复制
go run ./main.go

打开浏览器访问 localhost 即可看到 web 访问已经启动。

gin 运行模式

gin 内置提供了三种运行模式 :

代码语言:javascript
复制
const (
// DebugMode indicates gin mode is debug.
DebugMode = "debug"
// ReleaseMode indicates gin mode is release.
ReleaseMode = "release"
// TestMode indicates gin mode is test.
TestMode = "test"
)

我们可以在不同阶段设置不同的模式,如开发时使用 DebugMode、上线后使用 ReleaseMode。

开发时我们建议使用 r := gin.Default() 初始化 gin,会在终端内输出详细的运行信息。当项目准备上线时我们推荐使用 release 模式 :

代码语言:javascript
复制
package main

import "github.com/gin-gonic/gin"

func main() {
// 初始化 Gin 引擎
	gin.SetMode(gin.ReleaseMode)
	r := gin.New()
// 定义路由
	r.GET("/", func(c *gin.Context) {
		c.JSON(200, gin.H{
"message": "hello",
		})
	})
// 启动 web 服务
	r.Run(":80")
}

路由及路由分组

初始化 gin 引擎后获得 gin 引擎对象,通过引擎对象的 GET、POST、PUT、DELETE、Any 方法来定义路由

代码语言:javascript
复制
package main

import "github.com/gin-gonic/gin"

func main() {
// 初始化 Gin 引擎
	gin.SetMode(gin.ReleaseMode)
	r := gin.New()
// 定义首页路由
	r.GET("/", func(c *gin.Context) {
		c.JSON(200, gin.H{
"message": "hello",
		})
	})
// 定义关于其他路由
	r.GET("/News", func(ctx *gin.Context) {
		ctx.Writer.Write([]byte("新闻"))
	})
// 启动 web 服务
	r.Run(":80")
}

关于 Any

Any 代表路由可以接受 GET、POST、PUT、DELETE 任何模式,可以使用 ctx.Request.Method 获取请求类型 :

代码语言:javascript
复制
package main

import (
"fmt"

"github.com/gin-gonic/gin"
)

func main() {
// 初始化 Gin 引擎
	gin.SetMode(gin.ReleaseMode)
	r := gin.New()
// 定义首页路由
	r.GET("/", func(c *gin.Context) {
		c.JSON(200, gin.H{
"message": "hello",
		})
	})
// 定义关于其他路由
	r.Any("/Any", func(ctx *gin.Context) {
		requestMethod := ctx.Request.Method
		fmt.Printf("requestMethod: %v\n", requestMethod)
	})
// 启动 web 服务
	r.Run(":80")
}

路由分组

可以通过 r.Group() 函数来实现路由分组,例如将路由划分为网站前端和后端 :

代码语言:javascript
复制
package main

import (
"github.com/gin-gonic/gin"
)

func main() {
// 初始化 Gin 引擎
	r := gin.Default()

// 网站前台分组
	frontGroup := r.Group("/")
	frontGroup.GET("/", func(ctx *gin.Context) {
		ctx.Writer.Write([]byte("首页"))
	})

// 网站后台分组
	AdminGroup := r.Group("/Admin")
	AdminGroup.GET("/", func(ctx *gin.Context) {
		ctx.Writer.Write([]byte("后台首页"))
	})

	r.Run(":80")
}

访问 localhost 匹配网站前端路由;

访问 localhost/Admin 匹配网站后台路由;

路由文件抽离

可以将路由抽离为一个或者多个文件,使您的项目结构更加合理,下面我们样式将上面的路由抽离为前端、后端2个路由文件:

1. 创建文件 /router 文件夹

2. 创建 /router/front.go 文件,编写如下代码 :

代码语言:javascript
复制
package router

import "github.com/gin-gonic/gin"

// 网站前台分组
func Front(r *gin.Engine) {
	frontGroup := r.Group("/")
	frontGroup.GET("/", func(ctx *gin.Context) {
		ctx.Writer.Write([]byte("首页"))
	})
}

3. 创建 /router/admin.go 文件,编写如下代码 :

代码语言:javascript
复制
package router

import "github.com/gin-gonic/gin"

// 网站前台分组
func Admin(r *gin.Engine) {
// 网站后台分组
	AdminGroup := r.Group("/Admin")
	AdminGroup.GET("/", func(ctx *gin.Context) {
		ctx.Writer.Write([]byte("后台首页"))
	})
}

4. 在 main.go 中应用路由

代码语言:javascript
复制
import (
"gotest/router"

"github.com/gin-gonic/gin"
)

func main() {
// 初始化 Gin 引擎
	r := gin.Default()
	router.Front(r)
	router.Admin(r)
	r.Run(":80")
}

5. 运行,体验效果,至此路由文件抽离完毕。

路由参数及数据获取

Gin 路由参数概述

Gin 路由参数定义格式 :

代码语言:javascript
复制
r.GET("/:name/:age", func...)

实际访问路由格式 :

代码语言:javascript
复制
http://localhost/test/10

在函数中可以通过 : ctx.Param(key) 函数获取字符串形式的参数值。

代码语言:javascript
复制
// 网站前台分组
func Front(r *gin.Engine) {
	frontGroup := r.Group("/")

	frontGroup.GET("/:action", func(ctx *gin.Context) {
		action := ctx.Param("action")
		fmt.Printf("action: %v\n", action)
		ctx.Writer.Write([]byte("首页"))
	})
}

路由中间件

路由中间件介绍

路由中间件可以方便地实现权限检查、行为追踪等功能。通过 r.use() 函数可以方便地实现路由中间件。

如 在路由分组中实现中间件

代码语言:javascript
复制
package router

import (
"fmt"

"github.com/gin-gonic/gin"
)

// 定义中间件函数
func frontMiddleWare(ctx *gin.Context) {
println("我是前台路由中间件")
	fmt.Printf("请求路径: %v\n", ctx.Request.URL)
}

// 网站前台分组
func Front(r *gin.Engine) {
	frontGroup := r.Group("/")
	frontGroup.Use(frontMiddleWare)
	frontGroup.GET("/", func(ctx *gin.Context) {
		ctx.Writer.Write([]byte("首页"))
	})
}

以上代码演示了路由中间件的应用,您也可以将中间件抽离为独立的 go 文件,然后在其函数内实现中间件细节功能。

路由重定向及中间件跳出

重定向背景

在某些情况下,如会员登陆检查失败,需要从当前路由调整到登陆页面,可以使用 ctx.Redirect() 函数进行重定向。

终止路由继续运行

当某些条件不满足或者需要跳出当前路由时,需要使用 ctx.Abort() 函数终止路由继续运行。

演示代码

代码语言:javascript
复制
// 跳转到 Login
ctx.Redirect(302, "/Login")

// 跳出当前路由

ctx.Abort()

GET 和 POST 数据接收

Query 用于接收 GET 数据, 而 postFrom 用于接收 POST 数据。

url 及 post 值
代码语言:javascript
复制
url /post?id=1234&page=1 HTTP/1.1
Content-Type: application/x-www-form-urlencoded

POST数据 : name=manu&message=this_is_great
接收演示
代码语言:javascript
复制
func main() {
	router := gin.Default()

	router.POST("/post", func(c *gin.Context) {

		id := c.Query("id")
		page := c.DefaultQuery("page", "0")
		name := c.PostForm("name")
		message := c.PostForm("message")

		fmt.Printf("id: %s; page: %s; name: %s; message: %s", id, page, name, message)
	})
	router.Run(":8080")
}
// id: 1234; page: 1; name: manu; message: this_is_great

模型绑定和验证

数据绑定及验证概述

要将请求体绑定到结构体中,使用模型绑定。 Gin目前支持JSON、XML、YAML和标准表单值的绑定(foo=bar&boo=baz)。

Gin使用 go-playground/validator/v10 进行验证。 查看标签用法的全部文档。

使用时,需要在要绑定的所有字段上,设置相应的tag。 例如,使用 JSON 绑定时,设置字段标签为 json:"fieldname"。

Gin 的两类绑定方法

Must bindMethods - Bind, BindJSON, BindXML, BindQuery, BindYAML

这些方法属于 MustBindWith 的具体调用。 如果发生绑定错误,则请求终止,并触发 c.AbortWithError(400, err).SetType(ErrorTypeBind)。

Should bindMethods - ShouldBind, ShouldBindJSON, ShouldBindXML, ShouldBindQuery, ShouldBindYAML

这些方法属于 ShouldBindWith 的具体调用。 如果发生绑定错误,Gin 会返回错误并由开发者处理错误和请求。

使用 Bind 方法时,Gin 会尝试根据 Content-Type 推断如何绑定。 如果你明确知道要绑定什么,可以使用 MustBindWith 或 ShouldBindWith。

你也可以指定必须绑定的字段。 如果一个字段的 tag 加上了 binding:"required",但绑定时是空值, Gin 会报错。

数据验证

手册地址 : https://pkg.go.dev/gopkg.in/go-playground/validator.v10

使用演示

1. 安装 validator 包

代码语言:javascript
复制
go get github.com/go-playground/validator/v10

2. 在代码中引入工具包并使用

2.1 前端数据提交模板代码

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
    <form action="/" method="post">
        <table width="500">
            <tr>
                <td>姓名</td>
                <td><input type="text" name="Name" /></td>
            </tr>
            <tr>
                <td>年龄</td>
                <td><input type="text" name="Age" /></td>
            </tr>
            <tr>
                <td>手机号</td>
                <td><input type="text" name="Phone" /></td>
            </tr>
            <tr>
                <td>邮箱</td>
                <td><input type="text" name="Email" /></td>
            </tr>
            <tr>
                <td></td>
                <td>
                    <button type="submit">提交</button>
                </td>
            </tr>
        </table>
    </form>
</body>
</html>

2.2 后端数据验证演示代码

代码语言:javascript
复制
package main

import (
"fmt"
"html/template"
"regexp"

"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
)

// 创建一个结构体用于接收及验证POST数据
type Person struct {
	Name  string `validate:"min=1,max=10"`
	Age   int    `validate:"lte=100,gte=10"`
	Phone string `validate:"PhoneNumberCheck"`
	Email string `validate:"email"`
}

// 自定义验证函数 演示
func PhoneNumberCheck(fl validator.FieldLevel) bool {
	checkData := fl.Field().String()
	reg := regexp.MustCompile(`^1[0-9]{10,10}$`)
return reg.MatchString(checkData)
}

func main() {
// 初始化 Gin 引擎
	r := gin.Default()
// 提交页面
	r.GET("/", func(ctx *gin.Context) {
		template, err := template.ParseFiles("./templates/index.html")
if err != nil {
			fmt.Printf("err: %v\n", err)
		}
		template.Execute(ctx.Writer, nil)
	})
// 提交接收路由
	r.POST("/", func(ctx *gin.Context) {
		formData := &Person{}
// 表单数据映射
		ctx.Bind(formData)
		fmt.Printf("formData: %v\n", formData)
// 表单数据校验
		validate := validator.New()
// 添加自定义规则
		validate.RegisterValidation("PhoneNumberCheck", PhoneNumberCheck)
		err := validate.Struct(formData)
if err != nil {
			validationErrs := err.(validator.ValidationErrors)
			fmt.Printf("validationErrs: %v\n", validationErrs)
			fieldName := validationErrs[0].Field()
			ctx.JSON(200, gin.H{"errcode": 300001, "data": "字段 " + fieldName + " 数据错误"})
return
		}
	})
	r.Run(":80")
}
说明

1. 上面代码演示了使用 ctx.Bind() 函数将表单数据映射为结构体;

2. 使用 validate.New() 函数初始化验证对象;

3. 使用 validate.Struct() 来验证结构体;

4. 使用 validate.RegisterValidation() 来添加自定义验证规则,函数定义请参考 :

代码语言:javascript
复制
func PhoneNumberCheck(fl validator.FieldLevel) bool {
	checkData := fl.Field().String()
	reg := regexp.MustCompile(`^1[0-9]{10,10}$`)
return reg.MatchString(checkData)
}

5. 验证失败后返回错误信息切片,可以从错误数据中获取到字段名称及错误信息。

验证规则

更多规则请查阅官方手册,手册地址 :

https://pkg.go.dev/github.com/go-playground/validator/v10

Gin 中使用 template 模板引擎

模板引擎概述

在 Gin 中您可以通过 text/template 和 html/template 直接实现 html 模板渲染。关于模板引擎的知识请查阅本课程上一个章节。

演示代码
代码语言:javascript
复制
package main

import (
"fmt"
"html/template"

"github.com/gin-gonic/gin"
)

func main() {
// 初始化 Gin 引擎
	r := gin.Default()
	r.GET("/", func(ctx *gin.Context) {
		template, err := template.ParseFiles("./templates/index.html")
if err != nil {
			fmt.Printf("err: %v\n", err)
		}
		template.Execute(ctx.Writer, gin.H{"name": "lesscode.work"})
	})
	r.Run(":80")
}

可以通过 gin 提供的 html 渲染函数来实现模板渲染 :

使用 LoadHTMLGlob() 或者 LoadHTMLFiles()

代码语言:javascript
复制
func main() {
	router := gin.Default()
	router.LoadHTMLGlob("templates/*")
//router.LoadHTMLFiles("templates/template1.html", "templates/template2.html")
	router.GET("/index", func(c *gin.Context) {
		c.HTML(http.StatusOK, "index.tmpl", gin.H{
"title": "Main website",
		})
	})
	router.Run(":8080")
}

templates/index.tmpl

代码语言:javascript
复制
<html>
	<h1>
		{{ .title }}
	</h1>
</html>

使用不同目录下名称相同的模板

代码语言:javascript
复制
func main() {
	router := gin.Default()
	router.LoadHTMLGlob("templates/**/*")
	router.GET("/posts/index", func(c *gin.Context) {
		c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{
"title": "Posts",
		})
	})
	router.GET("/users/index", func(c *gin.Context) {
		c.HTML(http.StatusOK, "users/index.tmpl", gin.H{
"title": "Users",
		})
	})
	router.Run(":8080")
}

templates/posts/index.tmpl

代码语言:javascript
复制
{{ define "posts/index.tmpl" }}
<html>
<h1>
	{{ .title }}
</h1>
<p>Using posts/index.tmpl</p>
</html>
{{ end }}

templates/users/index.tmpl

代码语言:javascript
复制
{{ define "users/index.tmpl" }}
<html>
<h1>
	{{ .title }}
</h1>
<p>Using users/index.tmpl</p>
</html>
{{ end }}

自定义模板渲染器

你可以使用自定义的 html 模板渲染

代码语言:javascript
复制
import "html/template"
func main() {
	router := gin.Default()
	html := template.Must(template.ParseFiles("file1", "file2"))
	router.SetHTMLTemplate(html)
	router.Run(":8080")
}

自定义分隔符

你可以使用自定义分隔

代码语言:javascript
复制
r := gin.Default()
r.Delims("{[{", "}]}")
r.LoadHTMLGlob("/path/to/templates")

自定义模板功能

代码语言:javascript
复制
import (
    "fmt"
    "html/template"
    "net/http"
    "time"

    "github.com/gin-gonic/gin"
)

func formatAsDate(t time.Time) string {
    year, month, day := t.Date()
    return fmt.Sprintf("%d/%02d/%02d", year, month, day)
}

func main() {
    router := gin.Default()
    router.Delims("{[{", "}]}")
    router.SetFuncMap(template.FuncMap{
        "formatAsDate": formatAsDate,
    })
    router.LoadHTMLFiles("./testdata/template/raw.tmpl")
    router.GET("/raw", func(c *gin.Context) {
        c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{
            "now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC),
        })
    })

    router.Run(":8080")
}
  • 打包及部署

golang 打包

开发环境与运行环境一致

直接打包获得对应平台执行文件即可

代码语言:javascript
复制
go build ./main.go

开发环境与运行环境不一致

MacOs 平台
代码语言:javascript
复制
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o ./main ./main.go
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o ./main ./main.go
windows Poweshell
代码语言:javascript
复制
$ENV:CGO_ENABLED=0
$ENV:GOOS="linux"
$ENV:GOARCH="amd64"
go build -o ./main ./main.go
windows cmd
代码语言:javascript
复制
set CGO_ENABLED=0
set GOOS=linux
set GOARCH=amd64
go build -o ./main ./main.go

以服务形式运行于 linux 平台

创建服务

1 在 /etc/systemd/system/ 下创建服务, 如 goadmin.service

2 打开 goadmin.service, 编写如下命令 :

代码语言:javascript
复制
[Unit]
Description=Go Admin
After=network-online.target  
Wants=network-online.target 

[Service]
Type=simple
# 程序执行的目录
WorkingDirectory=/webs/***/
# 启动的脚本命令
ExecStart=/webs/***/main
# 重启条件
Restart=always
# 几秒后重启
RestartSec=5

[Install]
WantedBy=multi-user.target
开启 goadmin 服务
代码语言:javascript
复制
systemctl enable goadmin.service
启动服务
代码语言:javascript
复制
systemctl start goadmin.service
查看状态
代码语言:javascript
复制
systemctl status goadmin.service
重载服务
代码语言:javascript
复制
systemctl daemon-reload

通过 systemctl status 命令查看状态及内存占用

systemctl status 命令

可以使用 systemctl status 命令查看状态及内存占用情况,命令 :

代码语言:javascript
复制
systemctl status ***.service

输出

代码语言:javascript
复制
***.service - ***
    Loaded: loaded (/etc/systemd/system/***.service; enabled; vendor preset: enabled)
    Active: active (running) since Wed 2023-03-29 10:29:23 CST; 15min ago
    Main PID: 367** (main)
    Tasks: 5 (limit: 22696)
    Memory: 178.6M
    CGroup: /system.slice/***.service
           └─367*** /***/main

查看 web 服务 cpu 使用情况

通过 top 命令查看 ( -p 后的进程 ID 通过上面的 status 命令获取 ) :

代码语言:javascript
复制
top -p 367*** 

输出 :

代码语言:javascript
复制
3673281 root      20   0  933084 186940  13980 S   0.0   5.1   0:02.47 main

top 命令

代码语言:javascript
复制
1 top 命令执行后,按下 shift + m 可以实现按照内存使用量排序;
2 top 命令执行后,按下 shift + p 可以实现按照cpu使用量排序;

使用反向代理实现单服务器多站点部署

适用场景

当我们想在一个服务器上部署多个 go 站点时,每个go项目运行都需要独立的端口,但80端口只有一个,您可以通过 nginx 或者 apache 服务器的反向代理功能实现在一个服务器上部署多个 go 站点。还可以利用 nginx 反向代理实现负载均衡。

以 nginx 为例

Nginx(“engine x”)是一个高性能的HTTP和反向代理服务器,特点是占有内存少,并发能力强。

官网 : https://nginx.org/

下载、安装 nginx

下载地址 https://nginx.org/en/download.html

选择对应的 Nginx 版本下载并安装。

配置反向代理

模拟场景 :

代码语言:javascript
复制
go web server 项目运行端口 11022

nginx 反向代理配置 :

代码语言:javascript
复制
server {
    listen       80;
    server_name  localhost;

    #charset koi8-r;

    #access_log  logs/host.access.log  main;

    location / {
        proxy_pass http://127.0.0.1:11022;
        root   html;
        index  index.html index.htm;
    }
    # ......
}

配置多个 server {} 对应不同的 server_name 及 http://127.0.0.1:不同端口,即可实现基于 nginx 的反向代理功能,从而实现在一个服务器上部署多个 go 站点。

nginx 启动命令

代码语言:javascript
复制
start nginx.exe // 启动 nginx
nginx.exe -s stop  //停止 nginx
nginx.exe -s reload //重新加载 nginx
nginx.exe -s quit  //退出 nginx

apache 服务器实现反向代理

代码语言:javascript
复制
<VirtualHost *:80>
    ServerAdmin webmaster@example.com
    DocumentRoot "/******"
    ServerName localhost
    ServerAlias localhost
    <IfModule mod_proxy.c>
        ProxyRequests Off
        SSLProxyEngine on
        ProxyPass / http://127.0.0.1:11022/
        ProxyPassReverse / http://127.0.0.1:11022/
    </IfModule>
    #PROXY-END
    #......
</VirtualHost>
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-07-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序猿的栖息地 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 创建一个 web server
  • web server 的几个重要概念
  • web server 执行流程
  • go 语言实现 web server 的关键点
  • web server 工作原理
    • web server 的几个重要概念
    • web server 执行流程
  • handle 详解
    • golang 是如何处理 web 请求的?
    • ListenAndServe 函数
    • 创建 web 服务的第二种写法
    • Handler
  • go 语言内置的 handlers
    • http.NotFoundHandler
    • http.Redirect
    • http.StripPrefix()
    • http.TimeoutHandler
    • http.FileServer
  • http 请求相关知识
    • 概述
    • url 相关
    • header 相关
    • 通过 body 获取请求主体数据
    • 通过URL Query 接收 get 参数
  • 通过 form 获取表单及POST 数据
    • r.Form
    • r.PostForm
  • 通过 ParseMultipartForm 实现文件上传
    • go 语言代码
    • 前端 html
  • 处理静态文件
    • 实现代码示例
  • go 语言模板基础知识
    • 什么模板
    • go 语言的模板引擎
    • 关于模板
    • 示例代码
  • go 语言模板解析与执行
    • parseFiles()
    • parseGlob()
    • parse()
    • Must() 函数
    • 执行模板
  • action 相关知识
    • 什么是 action
    • 条件 action
    • with 改变 . 的作用范围
    • 包含某个模板
    • 综合示例
  • 模板自定义函数及管道
    • 自定义函数
    • 管道
  • 组合模板的应用
    • 组合模板概述
  • go 语言模板遍历语法及模板变量定义
    • go 语言模板遍历语法
    • 变量传递解决方案
    • 定义一个模板变量
  • Gin 快速入门
    • Gin 介绍
    • 安装 Gin
    • 快速开启 Web 服务
    • 快速开启 Web 服务
    • gin 运行模式
  • 路由及路由分组
    • 关于 Any
    • 路由分组
    • 路由文件抽离
  • 路由参数及数据获取
    • Gin 路由参数概述
  • 路由中间件
    • 路由中间件介绍
  • 路由重定向及中间件跳出
    • 重定向背景
    • 终止路由继续运行
    • 演示代码
  • GET 和 POST 数据接收
  • 模型绑定和验证
    • 数据绑定及验证概述
    • Gin 的两类绑定方法
    • 数据验证
  • Gin 中使用 template 模板引擎
    • 模板引擎概述
    • 使用 LoadHTMLGlob() 或者 LoadHTMLFiles()
    • 使用不同目录下名称相同的模板
    • 自定义模板渲染器
    • 自定义分隔符
    • 自定义模板功能
  • golang 打包
    • 开发环境与运行环境一致
    • 开发环境与运行环境不一致
  • 以服务形式运行于 linux 平台
    • 创建服务
  • 通过 systemctl status 命令查看状态及内存占用
    • systemctl status 命令
    • 查看 web 服务 cpu 使用情况
    • top 命令
  • 使用反向代理实现单服务器多站点部署
    • 适用场景
    • 以 nginx 为例
    • apache 服务器实现反向代理
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档