go-programming-tour-book / blog-service Goto Github PK
View Code? Open in Web Editor NEW《Go 语言编程之旅:一起用 Go 做项目》第二章:博客程序(HTTP Server)
License: Apache License 2.0
《Go 语言编程之旅:一起用 Go 做项目》第二章:博客程序(HTTP Server)
License: Apache License 2.0
internal\routers\router.go:39:19: undefined: middleware.Tracing
win10系统
go 1.16
复制文章源码或当前目录下源码到系统报错
`go: blog-service/pkg/app: package github.com/go-playground/universal-translator imported from implicitly required module; to add missing requirements, run:
go get github.com/go-playground/[email protected]
go: blog-service/internal/middleware: package github.com/go-playground/locales/en imported from implicitly required module; to add missing requirements, run:
go get github.com/go-playground/locales/[email protected]
go: blog-service/internal/middleware: package github.com/go-playground/locales/zh imported from implicitly required module; to add missing requirements, run:
go get github.com/go-playground/locales/[email protected]
go: blog-service/internal/middleware: package github.com/go-playground/locales/zh_Hant_TW imported from implicitly required module; to add missing requirements, run:
go get github.com/go-playground/locales/[email protected]
go: blog-service/internal/middleware: package github.com/go-playground/universal-translator imported from implicitly required module; to add missing requirements, run:
go get github.com/go-playground/[email protected]
package routers
import (
"github.com/gin-gonic/gin"
v1 "github.com/qiuyuhome/go-gin-blog-api/internal/routers/api/v1"
)
func NewRouter() *gin.Engine {
r := gin.New()
r.Use(gin.Logger())
r.Use(gin.Recovery())
article := v1.NewArticle()
tag := v1.NewTag()
apiv1 := r.Group("/api/v1")
// todo, 下面的 {} 的作用是什么?
{
apiv1.POST("/tags", tag.Create)
apiv1.DELETE("/tags/:id", tag.Delete)
apiv1.PUT("/tags/:id", tag.Update)
apiv1.PATCH("/tags/:id/state", tag.Update)
apiv1.GET("/tags", tag.List)
apiv1.POST("/articles", article.Create)
apiv1.DELETE("/articles/:id", article.Delete)
apiv1.PUT("/articles/:id", article.Update)
apiv1.PATCH("/articles/:id/state", article.Update)
apiv1.GET("/articles/:id", article.Get)
apiv1.GET("/articles", article.List)
}
return r
}
不理解这个 {} 的作用是什么? 去掉了也可以的。麻烦解答一下呗。
hello, There is a spelling error here.
File:internal/middleware/recovery.go:17:defailtMailer->defaultMailer
defer func() {
if err := recover(); err != nil {
global.Logger.WithCallersFrames().Errorf(c, "panic recover err: %v", err)
err := defailtMailer.SendMail(
global.EmailSetting.To,
fmt.Sprintf("异常抛出,发生时间: %d", time.Now().Unix()),
fmt.Sprintf("错误信息: %v", err),
)
if err != nil {
global.Logger.Panicf(c, "mail.SendMail err: %v", err)
}
app.NewResponse(c).ToErrorResponse(errcode.ServerError)
c.Abort()
}
}()
测试方式: ab -c 10 -n 100 localhost:8000/debug/vars
测试结果:
fatal error: concurrent map read and map write
goroutine 139 [running]:
runtime.throw(0x4a46303, 0x21)
/usr/local/go/src/runtime/panic.go:1116 +0x72 fp=0xc001b0c208 sp=0xc001b0c1d8 pc=0x4034962
runtime.mapaccess2(0x491bee0, 0xc0005cb080, 0xc001b0c288, 0x0, 0xc001a39601)
/usr/local/go/src/runtime/map.go:469 +0x258 fp=0xc001b0c248 sp=0xc001b0c208 pc=0x400fbd8
github.com/go-playground/validator/v10.(*Validate).RegisterTranslation(0xc00008e4e0, 0x4a31dce, 0xc, 0x4bbb0e0, 0xc001a3bb60, 0xc001acc690, 0x4a6d278, 0x0, 0x0)
/Users/hxj/godevspace/pkg/mod/github.com/go-playground/validator/[email protected]/validator_instance.go:261 +0xb0 fp=0xc001b0c2a8 sp=0xc001b0c248 pc=0x43ea6c0
github.com/go-playground/validator/v10/translations/zh.RegisterDefaultTranslations(0xc00008e4e0, 0x4bbb0e0, 0xc001a3bb60, 0x0, 0x62fdf00)
/Users/hxj/godevspace/pkg/mod/github.com/go-playground/validator/[email protected]/translations/zh/zh.go:1321 +0x4f9 fp=0xc001b0d3b0 sp=0xc001b0c2a8 pc=0x480bfd9
github.com/go-programming-tour-book/blog-service/internal/middleware.Translations.func1(0xc000398000)
/Users/hxj/Work/work_go/go-programming-tour-book/blog-service/internal/middleware/translations.go:30 +0x1ea fp=0xc001b0d458 sp=0xc001b0d3b0 pc=0x4816a8a
github.com/gin-gonic/gin.(*Context).Next(0xc000398000)
/Users/hxj/godevspace/pkg/mod/github.com/gin-gonic/[email protected]/context.go:161 +0x3b fp=0xc001b0d478 sp=0xc001b0d458 pc=0x45e9f8b
github.com/go-programming-tour-book/blog-service/internal/middleware.ContextTimeout.func1(0xc000398000)
/Users/hxj/Work/work_go/go-programming-tour-book/blog-service/internal/middleware/context_timeout.go:16 +0x14f fp=0xc001b0d4f8 sp=0xc001b0d478 pc=0x48161df
github.com/gin-gonic/gin.(*Context).Next(0xc000398000)
/Users/hxj/godevspace/pkg/mod/github.com/gin-gonic/[email protected]/context.go:161 +0x3b fp=0xc001b0d518 sp=0xc001b0d4f8 pc=0x45e9f8b
github.com/go-programming-tour-book/blog-service/internal/middleware.RateLimiter.func1(0xc000398000)
/Users/hxj/Work/work_go/go-programming-tour-book/blog-service/internal/middleware/limiter.go:23 +0x89 fp=0xc001b0d568 sp=0xc001b0d518 pc=0x4816449
修复方式: 去掉 translations.go中间件,将中间件中的函数内容放到main.go文件中,函数体:
// 在global包中定义全局变量
var Trans ut.Translator
// InitTrans 初始化翻译器
func InitTrans(locale string) (err error) {
// 修改gin框架中的Validator引擎属性,实现自定制
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
zhT := zh.New() // 中文翻译器
enT := en.New() // 英文翻译器
// 第一个参数是备用(fallback)的语言环境
// 后面的参数是应该支持的语言环境(支持多个)
// uni := ut.New(zhT, zhT) 也是可以的
uni := ut.New(enT, zhT, enT)
// locale 通常取决于 http 请求头的 'Accept-Language'
var ok bool
// 也可以使用 uni.FindTranslator(...) 传入多个locale进行查找
global.Trans, ok = uni.GetTranslator(locale)
if !ok {
return fmt.Errorf("uni.GetTranslator(%s) failed", locale)
}
// 注册翻译器
switch locale {
case "en":
err = enTranslations.RegisterDefaultTranslations(v, global.Trans)
case "zh":
err = zhTranslations.RegisterDefaultTranslations(v, global.Trans)
default:
err = enTranslations.RegisterDefaultTranslations(v, global.Trans)
}
return
}
return
}
在main()函数中调用:
func main() {
if err := InitTrans("zh"); err != nil {
fmt.Printf("init trans failed, err:%v\n", err)
return
}
......
}
修改pkg/app/form.go文件中的
BindAndValid(){
// 直接用全局变量
for key, value := range verrs.Translate(global.Trans) {
....
}
}
报错内容:
init.setupSetting err: While parsing config: yaml: line 11: did not find expected key
我将yaml直接替换为示例文件中的 yaml 编译是没问题的,但是把示例文件中除此章节涉及内容外多余部分删除,只保留此小节涉及内容,编译就会报错,挺奇怪。
反复检查很多次,并不是 yaml 格式的问题。
time.Now().Local().UnixNano() 的Local多此一举 时间戳是全世界统一的
if len(l.fields) > 0 也可以去掉
r.POST("/auth", api.GetAuth)改为r.GET("/auth", api.GetAuth)
internal/model 中 Update方法里面 SQL有问题,("id = ? ND is_del = ?", t.ID),缺少了t.t.IsDel。
程序启动:
global.AppSetting.DefaultContextTimeout *= time.Second
global.JWTSetting.Expire *= time.Second
global.ServerSetting.ReadTimeout *= time.Second
global.ServerSetting.WriteTimeout *= time.Second
热更新:
func (s *Setting) ReloadAllSection() error {
for k, v := range sections {
err := s.ReadSection(k, v)
if err != nil {
return err
}
}
return nil
}
第二章 2.6 节中, models 回调用的是 gorm 1.0 版本,请问在 gorm 2.0 版本中如何处理?
struct field code has json tag but is not exported。在网上找发现是字段首字母没大写,但用了json导致的。我看code,msg,details是通过下面的方法返回的,这样写有什么好处吗?
在使用 http://127.0.0.1:8000/api/v1/tags?state=6 时候
global.Logger.Errorf(c, "app.BindAndValid errs: %v", errs)这行 panic
err: Key "X-Trace-ID" does not exist
项目中为
地址
// @Param tag_id body string true "标签ID"
// @Param title body string true "文章标题"
// @Param desc body string false "文章简述"
// @Param cover_image_url body string true "封面图片地址"
// @Param content body string true "文章内容"
// @Param created_by body int true "创建者"
实质应为
type Article struct {
*Model
Title string `json:"title"`
Desc string `json:"desc"`
Content string `json:"content"`
CoverImageUrl string `json:"cover_image_url"`
State uint8 `json:"state"`
}
@Param - body Article true "标签ID"
我是在get tags里面返回response之前,加上了一个time.Sleep(10 * time.Second) ,然后在yaml里面设置的时间是1s,但是没有生效啊
222
这里的 swagger 注释应该是 model.Tag
,而不是model.TagSwagger
; article.go
这里的注释同样的错误,应该是model.Article
日志信息:
2020/07/16 00:03:10 {"caller":["/home/vaniot/dev/blog-service/main.go: 21 main.init.0"],"level":"error","message":"svc.UpdateArticle err: sql: expected 10 arguments, got 9","time":1594828990988757269}
在知乎买的书,里面的sql竟然是图片截图...
配置文件热更新后,对于某些已使用的地方是无效的
main.go
// 对于以下变量即使global.ServerSetting发生变化也是不会更新的
gin.SetMode(global.ServerSetting.RunMode)
router := routers.NewRouter()
s := &http.Server{
Addr: ":" + global.ServerSetting.HttpPort,
Handler: router,
ReadTimeout: global.ServerSetting.ReadTimeout,
WriteTimeout: global.ServerSetting.WriteTimeout,
MaxHeaderBytes: 1 << 20,
}
...
router.go
...
// 因为超时中间件参数是值传递,所以即使global.AppSetting.DefaultContextTimeout发生改变,该中间件还是只会使用首次注册时的参数值
r.Use(middleware.ContextTimeout(global.AppSetting.DefaultContextTimeout))
解决:
修改context_timeout.go
ContextTimeout的值传递改为引用传递
func ContextTimeout(d *time.Duration) gin.HandlerFunc {
return func(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), *d)
defer cancel()
c.Request = c.Request.WithContext(ctx)
c.Next()
}
}
并发情况下会产生map线程安全问题
按照书上的代码,我可以监听到热更新,接着我想测试一下是否可用。
我把runmode从debug改成了test,当我访问一个接口的时候控制台仍然会有logger输出,也就是说gin的模式并没有被更新。
我在想是不是调用了reloadallsection这个方法的时候,只是把global里的变量改了。
类似的情况还可以比如说更改端口号,更改数据库密码等等。都是只能监听到这些值的更新,但并没有影响到程序,还是得重启一遍才生效。
请大神们指点一下。
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.