这个context 之前没有接触。现在开始重新学习
web 框架的gin
http
json
protocol buffer
gob
RPC
6
那天有空再仔细看一下
https://draveness.me/golang/docs/part3-runtime/ch06-concurrency/golang-context/
context
context
https://draveness.me/golang/docs/part3-runtime/ch06-concurrency/golang-context/
https://segmentfault.com/a/1190000040917752
https://pkg.go.dev/context@go1.7beta1#Background
https://www.cnblogs.com/qcrao-2018/p/11007503.html
https://segmentfault.com/a/1190000039294140
context 包
多个协程之间进行信息传递,包括层层的递进顺序传递
当顶层context被取消或者超时的时候,所有从这个顶层创建的context也应该结束。
context包实现了在程序协程直接共享状态变量的方法,在被调用程序单元的外部,通过上写完变量ctx ,讲过期或取消信号传递给调用的程序单元
go 中开启协程很简单,但是操作起来不容易
sync包可以进行原子操作
用channel可以进行PV操作。可以进行多个协程之间的通讯。
context的结构
type context struct{
Done() <-chan struct
Err() error
deadline()(deadline time ,ok bool )
value(key interface{}) interface{}
}
Done 返回一个close 的channel
err 差错检测
deadline 返回结束的时间,和是否有效
value是共享数据
顶层会创建context
var ctx, cancel = context.WithCancel(context.Background())
var ctxTwo, cancelTwo = context.WithTimeout(context.Background(), 7*1e9)
设置共享参数
ctx = context.WithValue(ctx, 1, 12345)
可以看一下注释return 的结果
完整代码
package main
import (
"context"
"errors"
"fmt"
"time"
)
func childrenGoroutine(ctx context.Context) {
var value = ctx.Value(1)
fmt.Println(value)
var errorContext = ctx.Err()
for {
time.Sleep(1e9)
select {
case <-ctx.Done():
fmt.Printf("this is over ")
errorContext = errors.New("channel shut down")
fmt.Println(errorContext)
return
default:
if deadTime, ok := ctx.Deadline(); ok {
fmt.Println(deadTime)
} else {
fmt.Println("time is arrived")
}
}
}
}
/*
所以在大多数情况下,我们都使用context.Background作为起始的上下文向下传递。
上面的两种方式是创建根context,不具备任何功能
*/
func initContext() {
var ctx, cancel = context.WithCancel(context.Background())
ctx = context.WithValue(ctx, 1, 12345)
go childrenGoroutine(ctx)
var ctxTwo, cancelTwo = context.WithTimeout(context.Background(), 7*1e9)
go childrenGoroutine(ctxTwo)
time.Sleep(8 * 1e9)
cancel()
cancelTwo()
}
func main() {
initContext()
time.Sleep(10 * 1e9)
}
http
主要几点
- 基本HTTP
- HTTPS原理和实现
- gin框架
最后提醒一句,重点是服务端。客户端我会尽量使用andorid 去处理。因为前端也很卷了
https://gin-gonic.com/zh-cn/docs/quickstart/
https://www.bilibili.com/video/BV13g41157hK?p=3&vd_source=aa1af4ac07546d4eabfe89e8a6128265
https://www.bilibili.com/video/BV1Ti4y1w7Um?spm_id_from=333.337.search-card.all.click&vd_source=aa1af4ac07546d4eabfe89e8a6128265
https://www.bilibili.com/video/BV1gJ411p7xC?p=3&vd_source=aa1af4ac07546d4eabfe89e8a6128265
https://juejin.cn/post/6952340347280162852
首先是基本的HTTP
然后是gin框架
ORM框架
学习redis
首先是GIN的基本部分
GIN是很高效的一个框架
零分配路由。
仍然是最快的 http 路由器和框架。
完整的单元测试支持。
实战考验。
API 冻结,新版本的发布不会破坏你的代码。
然后写的时候尽量去满足RESTful风格
GET用来获取资源
POST用来新建资源
PUT用来更新资源
DELETE用来删除资源。
router.GET("/AsciiJSON", BackASCIIOnlyJSON)
router.GET("/login", HTMLRendering)
router.POST("/postMethod", PostMethod)
router.POST("/uploadOneFile", multipleFilesUpload)
router.PUT("/putMethod")
router.DELETE("/deleteMethod")
这里是基本的流程
想一下context的创建流程
创建顶部的context 然后进行向下传播
但顶部取消后,所有的都要取消
虽然我也不知道gin.context里面到底封装了什么
等会看一下源码吧
最基本的JOSN
这里提一嘴
gin.H里面实现的也是go原生的包
如果直接传struct gin会自动转换为JSON
func BackJSON(ctx *gin.Context) {
var myself = PersonInfo{
Name: "wyx",
Age: 21,
Info: "this is sister of dc",
}
/*
ctx.JSON(http.StatusOK, gin.H{
"name": "sisterOfDc",
"age": "21",
})
*/
ctx.JSON(http.StatusOK, myself)
}
这里我对HTML的搭建进行一些省略。因为
现在前后端都分离了
前端网页是VUE
安卓是直接请求JSON回来
微信也是直接请求JSON回去
当然肯定还是有点的
请求,拿到参数
如果是POST请求
拿到参数的主要为几个函数
var personInfo = ctx.PostForm("Name")
var personInfo.Name=ctx.DefaultPostForm()
第二个参数是没有输入默认返回的值
func PostMethod(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "login.html", gin.H{
"name": "ok",
})
var personInfo = new(Person)
personInfo.Name = ctx.PostForm("Name")
/*
personInfo.Name=ctx.DefaultPostForm()
第二个参数是没有输入默认返回的值
*/
personInfo.Info = ctx.PostForm("Info")
fmt.Println(personInfo)
}
这里是拿GIT请求的
函数是
query
queryfault
func HTMLRendering(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "login.html", gin.H{
"name": "sister of dc",
})
var personInfo = new(Person)
personInfo.Name = ctx.Query("Name")
personInfo.Info = ctx.Query("Info")
fmt.Println(personInfo)
//SecureJSON
}
如果是拿到文件的。
需要设置内存限制,默认32MB MaxMultipartMemory
单个文件
func uploadOneFile(ctx *gin.Context) {
var file, ErrorFile = ctx.FormFile("file")
if ErrorFile != nil {
ErrorFile = errors.New("file is filed")
fmt.Println(ErrorFile)
}
var dst = "./" + file.Filename
fmt.Println(file.Filename)
var ErrorSava = ctx.SaveUploadedFile(file, dst)
if ErrorSava != nil {
ErrorSava = errors.New("save is filed")
fmt.Println(ErrorSava)
}
ctx.JSON(http.StatusOK, gin.H{
"fileName": file.Filename,
})
}
多个文件中。是file。看传过来的key是什么
多个文件也不能超过内存限制
大文件上传看一下
func multipleFilesUpload(ctx *gin.Context) {
var form, ErrorForm = ctx.MultipartForm()
if ErrorForm != nil {
ErrorForm = errors.New("form read is filed")
fmt.Println(ErrorForm)
}
var files = form.File["file"]
for _, file := range files {
fmt.Println(file.Filename)
}
}
在for循环中拿到file中再去开单个文件的读写
简单的HTML的部分
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>login</title>
</head>
<body>
<form action="" method="get">
<a>this is get Method</a>
<label>
First name:
<input type="text" name="Name"/>
</label>
<label>
Last name:
<input type="text" name="Info"/>
</label>
<input type="submit" value="Submit" />
</form>
<form action="http://192.168.240.131:8090/postMethod" method="POST">
<a>this is post Method</a>
<label>
First name:
<input type="text" name="Name"/>
</label>
<label>
Last name:
<input type="text" name="Info"/>
</label>
<input type="submit" value="Submit" />
</form>
<form action="http://192.168.240.131:8090/uploadOneFile" method="post" enctype="multipart/form-data">
<div>
<label for="file">Choose file to upload</label>
<input type="file" id="file" name="file" multiple>
</div>
<div>
<input type="submit" value="Submit" />
</div>
</form>
</body>
</html>
get post put delete 是前端的事情了
中间件
中间件的作用
对一组接口进行统一的操作
实现类似于横切的关注点
记录Log,错误handler 对部分接口进行鉴权
gin中间件中使用goroutine
当在中间件或handler中启动新的goroutine时,不能使用原始的上下文(c *gin.Context),必须使用其只读副本(c.Copy())。
这个问题在context中也说了。gin.context是gin自定义的。必须要去看源码