第一个Go Web 程序
package main
import (
"fmt"
"net/http"
)
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "hello world")
}
func main() {
server := &http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/", hello)
server.ListenAndServe()
}
跑起来的效果:
Gin框架的使用
gin示例
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
//创建一个默认的路由引擎
r := gin.Default()
// GET:请求方式;/hello:请求的路径
// 当客户端以GET方法请求/hello路径时,会执行后面的匿名函数
r.GET("/hello", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "hello go",
})
})
r.Run()
}
RESTful API(后面会用go实现)
REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”或“表现层状态转化”。
简单来说,REST的含义就是客户端与Web服务器之间进行交互的时候,使用HTTP协议中的4个请求方法代表不同的动作。
- GET用来获取资源
- POST用来新建资源
- PUT用来更新资源
- DELETE用来删除资源
只要API程序遵循了REST风格,那就可以称其为RESTful API。目前在前后端分离的架构中,前后端基本都是通过RESTful API来进行交互。
Gin框架支持RESTful API的开发。
示例:
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/book", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "GET",
})
})
r.POST("/book", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "POST",
})
})
r.DELETE("/book", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "DELETE",
})
})
r.PUT("/book", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "PUT",
})
})
r.Run()
}
搭配Postman使用
template 初识
在下面的代码片段里面涉及到了 如何 自定义模版函数 加载静态模版 的方法:
package main
import (
"github.com/gin-gonic/gin"
"html/template"
"net/http"
)
//自定义模版函数
func main() {
r := gin.Default()
//加载静态模板
r.Static("/xxx", "./statics")
// 自定义模版函数
r.SetFuncMap(template.FuncMap{
"safe": func(str string) template.HTML {
return template.HTML(str)
},
})
//加载模版
r.LoadHTMLGlob("templates/*")
r.GET("/index", func(c *gin.Context) {
c.HTML(http.StatusOK, "index.html", "<a href='https://yoboot.github.io'>小王的bolg</a>")
})
r.Run(":9090")
}
//文件路径:templates/*
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div>{{ . | safe }}</div>
</body>
</html>
JSON渲染
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
//1gin.H 是map[string]interface{}的缩写
r.GET("/index", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"小王": 18, "牛魔王": "我卡拉卡"})
})
type msg struct {
Name string `json:"name"`
Age int `json:"age"`
}
r.GET("/msg", func(c *gin.Context) {
data := msg{
Age: 18,
Name: "小王子",
}
// 2.使用结构体
c.JSON(http.StatusOK, data)
})
r.Run()
}
获取参数
获取querystring参数
querystring 指的是URL中?后面携带的参数,例如:
/user/search?username=小王子&address=沙河。
获取请求的querystring参数的方法如下:
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
// querystring
r := gin.Default()
r.GET("/web", func(c *gin.Context) {
// http://localhost:8080/web?query=小王
// 获取浏览器那边发送请求携带的参数 query string 参数
//name := c.Query("query") //通过Query获取请求中携带的querystring参数
//name, ok := c.GetQuery("query") //通过GetQuery获取参数,获取不到第二个参数返回bool值
//if !ok {
// //获取不到
// name = "sombody"
//}
name := c.DefaultQuery("query", "sombody") //通过DefaultQuery获取参数,获取不到返回默认值
c.JSON(http.StatusOK, name)
})
r.Run()
}
获取form 参数
login.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<form action="/login" method="post" novalidate autocomplete="off">
<div>
<label for="username">username:</label>
<input type="text" name="username" id="username">
</div>
<div>
<label for="password">password</label>
<input type="password" name="password" id="password">
</div>
<div>
<input type="submit" value="登录">
</div>
</form>
</body>
</html>
index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1>Hello,{{.Name}}</h1>
<p>你的密码是:{{.Password}}</p>
</body>
</html>
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
r.LoadHTMLFiles("./login.html", "./index.html")
r.GET("/login", func(c *gin.Context) {
c.HTML(http.StatusOK, "login.html", nil)
})
//login post
r.POST("/login", func(c *gin.Context) {
//第一种获取form表单提交数据的方法 PostForm
/*username := c.PostForm("username")
password := c.PostForm("password")
*/
// 第二种获取form表单提交数据的方法 DefaultPostForm
// DefaultPostForm 找不到数据返回默认值,值得注意的是这里说的是你提交的参数找不到
/*username := c.DefaultPostForm("username", "somebody")
password := c.DefaultPostForm("password", "0000")
*/
//第三种获取方法 GetPostForm 获取不到则返回bool值
username, ok := c.GetPostForm("username")
if !ok {
username = "somebody"
}
password, ok := c.GetPostForm("password")
if !ok {
password = "0000"
}
c.HTML(200, "index.html", gin.H{
"Name": username,
"Password": password,
})
})
r.Run()
}
获取URL路径参数
http://localhost:8080/user/小王/庆阳
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/user/:username/:address", func(c *gin.Context) {
// Param 获取path参数
username := c.Param("username")
address := c.Param("address")
c.JSON(200, gin.H{
"message": "ok",
"username": username,
"address": address,
})
})
r.Run()
}
执行结果:
{“address”:“庆阳”,“message”:“ok”,“username”:“小王”}
参数绑定
为了能够更方便的获取请求相关参数,提高开发效率,我们可以基于请求的Content-Type识别请求数据类型并利用反射机制自动提取请求中QueryString、form表单、JSON、XML等参数到结构体中。 下面的示例代码演示了.ShouldBind()强大的功能,它能够基于请求自动提取JSON、form表单和QueryString类型的数据,并把值绑定到指定的结构体对象。
inde.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>index</title>
</head>
<body>
<form action="/form" method="post">
用户名:
<input type="text" name="username">
密码:
<input type="password" name="password">
<input type="submit" value="提交">
</form>
</body>
</html>
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
type UserInfo struct {
Username string `form:"username"`
Password string `form:"password"`
}
func main() {
r := gin.Default()
r.LoadHTMLFiles("./index.html")
r.GET("/user", func(c *gin.Context) {
u := UserInfo{}
/*u.Username = c.Query("username")
u.Password = c.Query("password")*/
//与上面相比ShouldBind()展示了它的强大之处
err := c.ShouldBind(&u)
if err != nil {
c.JSON(http.StatusBadGateway, gin.H{
"err": err.Error(),
})
} else {
fmt.Println(u)
c.JSON(200, gin.H{
"message": "ok",
})
}
})
r.GET("/index", func(c *gin.Context) {
c.HTML(200, "index.html", nil)
})
r.POST("/form", func(c *gin.Context) {
u := UserInfo{}
err := c.ShouldBind(&u)
if err != nil {
c.JSON(http.StatusBadGateway, gin.H{
"err": err.Error(),
})
} else {
fmt.Println(u)
c.JSON(200, gin.H{
"message": "ok",
})
}
})
//与postman搭配
r.POST("/json", func(c *gin.Context) {
u := UserInfo{}
err := c.ShouldBind(&u)
if err != nil {
c.JSON(http.StatusBadGateway, gin.H{
"err": err.Error(),
})
} else {
fmt.Println(u)
c.JSON(200, gin.H{
"message": "ok",
})
}
})
r.Run()
}
文件上传
通过网络将本地文件从客户端上传到服务端
单个文件上传
前端代码:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<title>上传文件示例</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="f1">
<input type="submit" value="上传">
</form>
</body>
</html>
后端gin代码
package main
import (
"github.com/gin-gonic/gin"
"net/http"
"path"
)
func main() {
r := gin.Default()
r.LoadHTMLFiles("./index.html")
r.GET("/index", func(c *gin.Context) {
c.HTML(200, "index.html", nil)
})
r.POST("/upload", func(c *gin.Context) {
//从请求中读取文件
f, err := c.FormFile("f1")
if err != nil {
c.JSON(http.StatusBadGateway, gin.H{
"error": err.Error(),
})
} else {
//将读取到的文件保存到本地(服务器)
//dst := fmt.Sprint("./%s", f.Filename)
dst := path.Join("./", f.Filename)
//上传文件到指定目录
c.SaveUploadedFile(f, dst)
c.JSON(200, gin.H{
"message": "ok",
})
}
})
r.Run()
}
多个文件上传
func main() {
router := gin.Default()
// 处理multipart forms提交文件时默认的内存限制是32 MiB
// 可以通过下面的方式修改
// router.MaxMultipartMemory = 8 << 20 // 8 MiB
router.POST("/upload", func(c *gin.Context) {
// Multipart form
form, _ := c.MultipartForm()
files := form.File["file"]
for index, file := range files {
log.Println(file.Filename)
dst := fmt.Sprintf("C:/tmp/%s_%d", file.Filename, index)
// 上传文件到指定的目录
c.SaveUploadedFile(file, dst)
}
c.JSON(http.StatusOK, gin.H{
"message": fmt.Sprintf("%d files uploaded!", len(files)),
})
})
router.Run()
}
HTTP重定向
r.GET("/test", func(c *gin.Context) {
c.Redirect(http.StatusMovedPermanently, "http://www.sogo.com/")
})
路由重定向
路由重定向,使用HandleContext:
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
r := gin.Default()
r.GET("/a", func(c *gin.Context) {
c.Request.URL.Path = "/b"
r.HandleContext(c)
})
r.GET("/b", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Yoboot",
})
})
r.Run()
}
路由组
这里先介绍两个路由 Any 和 NoRoute
一个可以匹配所有请求方法的Any:文章来源:https://www.toymoban.com/news/detail-832206.html
r.Any("./index", func(c *gin.Context) {
switch c.Request.Method {
case http.MethodGet:
c.JSON(200, gin.H{"message": "index get"})
case http.MethodPut:
c.JSON(200, gin.H{"message": "index put"})
case http.MethodPost:
c.JSON(200, gin.H{"message": "index post"})
}
})
```
NoRoute 为没有配置处理函数的路由添加处理程序,默认情况下它返回404代码
```go
//NoRoute 没有定义的路由
r.NoRoute(func(c *gin.Context) {
c.JSON(http.StatusNotFound, gin.H{"msg": "此路由没有定义"})
})
路由组文章来源地址https://www.toymoban.com/news/detail-832206.html
//把公用的前缀提取出来,创建一个路由组
videoGroup := r.Group("/video")
{
videoGroup.GET("/index", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"msg": "/video/index"})
})
videoGroup.GET("/xx", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"msg": "/video/xx"})
})
videoGroup.GET("/oo", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"msg": "/video/oo"})
})
}
到了这里,关于Go Web 开发的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!