精华内容
下载资源
问答
  • 启动与配置就不说了,网上很多 配置好了启动 beego 的发布程序 supervisorctl start beepkg 然后报错: ERROR (spawn error) 查看日志输出: (需要配置: redirect_stderr = true ) panic: you are in dev...

    supervisor启动与配置就不说了,网上很多

    配置好了启动beego的发布程序

    supervisorctl start beepkg

    然后报错:

    ERROR (spawn error)

    查看日志输出:

    (需要配置:redirect_stderr = true)

    panic: you are in dev mode. So please set gopath

    恐慌了, 居然说我没有配置 GOPATH, 我明明配置了啊

    原来Supervisor需要手动配置环境变量,在supervisor.conf中配置:
    environment=GOPATH="/home/username/go"

    重启supervisor service supervisord restart 然后, 然后就好了

    如果你beego发布的程序是prod模式就避免这个麻烦了


    以上问题其实是在linux下使用sudo方式来启动supervisor管理的服务导致的,
    我使用的系统是CentOS, 在CentOS上配置了环境变量(/etc/profile适用所有用户),
    不知道为什么sudo下不能读取GOPATH,
    所以就在supervisor.conf中配置GOPATH来跳过这个问题.
    至于sudo下的环境变量问题, 有时间再研究一下.

    转载于:https://my.oschina.net/imhuayi/blog/630970

    展开全文
  • beego安装启动

    2020-05-29 15:51:37
    beego 是基于八大独立的模块构建的,是一个高度解耦的框架 1、安装beego a)go get github.com/astaxie/beego b)或直接https://github.com/astaxie/beego 下载zip包,然后解压到$GOPATH/src/github.com下 2、安装...

    beego 是基于八大独立的模块构建的,是一个高度解耦的框架

    1、安装beego

    a)go get github.com/astaxie/beego 
    b)或直接https://github.com/astaxie/beego 下载zip包,然后解压到$GOPATH/src/github.com下
    

    2、安装bee

    beego 的项目基本都是通过bee 命令来创建的。
    a)go get github.com/beego/bee
    b)或直接https://github.com/beego/bee  下载zip包,然后解压到$GOPATH/src/github.com/beego下
    进入到$GOPATH/src/github.com/beego/bee 下执行 go clean -r -i ;go install -v安装bee
    默认安装到$GOPATH/bin下,如果设置了GOBIN,则安装到此目录,到次目录执行./bee即可
    

    3、创建项目

    可通过ln  -s /home/gobin/bee /usr/local/bin  将bee进行软连接,创建快捷方式。
    默认会在$GOPATH/src下创建名为 myproject的项目
    

    在这里插入图片描述
    除了使用new 命令用新建 Web 项目,还可以使用api 命令就是用来创建 API 应用:
    在这里插入图片描述

    4、启动项目

    进入myproject目录,执行bee run命令启动项目
    在这里插入图片描述
    在浏览器输入http://localhost:8080/就可以看到效果
    在这里插入图片描述

    展开全文
  • 一、前言前面 我们探究了如何搭建一个简单的beego应用,本节我们看其启动流程。二、启动流程首先快速从下图复习下上节的mybeen应用的结构:然后我们看main.go运行...

    一、前言

    前面 我们探究了如何搭建一个简单的beego应用,本节我们看其启动流程。

    二、启动流程

    首先快速从下图复习下上节的mybeen应用的结构:640?wx_fmt=png

    然后我们看main.go运行时候,如何一步步来启动httpserver的,其启动时序图如下:640?wx_fmt=png

    • 如上时序图步骤1,2,3首先调用了beego.go文件的init方法,该方法内步骤4使用newBconfig方法创建了一个默认配置类,比如http服务监听端口默认为8080等等640?wx_fmt=png步骤5则加载项目目录conf下的app.conf文件640?wx_fmt=png然后步骤6解析该文件中配置项到全局配置BConfig中。

    • 时序图中步骤7才是真正开始执行我们的main.go中的main函数,其中会调用beego的Run方法,其内部首先调用initBeforeHTTPRun方法,该方法代码如下:

    func initBeforeHTTPRun() {	
        //添加内置hooks	
        AddAPPStartHook(	
            registerMime,	
            registerDefaultErrorHandler,	
            registerSession,	
            registerTemplate,	
            registerAdmin,	
            registerGzip,	
        )	
        //顺序执行hook方法	
        for _, hk := range hooks {	
            if err := hk(); err != nil {	
                panic(err)	
            }	
        }	
    }
    • 如上时序图步骤13具体启动http服务,根据app.conf 中配置不同启动不同的httpserver,默认是正常模式,如果设置EnableFcgi为true则启动cgi服务,如果设置Graceful为true则启动优雅重启服务。这些后面具体讲解。

    其中启动普通httpserver代码如下:

    //1. 创建含有一个元素的bool类型通道	
    var endRunning = make(chan bool, 1)	
    //2.开启gorotuine启动httpserver	
    if BConfig.Listen.EnableHTTP {	
            go func() {	
                app.Server.Addr = addr	
                logs.Info("http server Running on http://%s", app.Server.Addr)	
                if BConfig.Listen.ListenTCP4 {	
                    ln, err := net.Listen("tcp4", app.Server.Addr)	
                    if err != nil {	
                        logs.Critical("ListenAndServe: ", err)	
                        time.Sleep(100 * time.Microsecond)	
                        //向通道写入元素	
                        endRunning <- true	
                        return	
                    }	
                    if err = app.Server.Serve(ln); err != nil {	
                        logs.Critical("ListenAndServe: ", err)	
                        time.Sleep(100 * time.Microsecond)	
                        //向通道写入元素	
                        endRunning <- true	
                        return	
                    }	
                } else {	
                    if err := app.Server.ListenAndServe(); err != nil {	
                        logs.Critical("ListenAndServe: ", err)	
                        time.Sleep(100 * time.Microsecond)	
                        //向通道写入元素	
                        endRunning <- true	
                    }	
                }	
            }()	
        }	
    //3.等待http服务终止。	
    <-endRunning

    可知具体启动了一个新goroutine来启动服务,并且当前goroutine会在服务处理请求过程中使用代码3挂起当前goroutine,当新goroutine内服务结束后会向通道endRunning写入一个数据,然后当前goroutine就会返回了。

    到这里httpserver启动概要流程已经完毕。

    三、总结

    本文我们简单额剖析了beego创建的应用的启动流程。

    展开全文
  • Beego

    2021-03-28 21:01:44
    bee 工具 本是一个为了协助快速开发 beego 项目而创建的项目, 通过 bee 可以快速创建项目、实现热编译、开发测试以及开发完之后打包发布的一整套从创建、开发到部署的方案。 go get github.com/beego/bee 安装完...

    bee工具

    介绍

    bee 工具 本是一个为了协助快速开发 beego 项目而创建的项目,
    通过 bee 可以快速创建项目、实现热编译、开发测试以及开发完之后打包发布的一整套从创建、开发到部署的方案。
    go get github.com/beego/bee
    安装完之后,bee可执行文件 配置成环境变量。

    常用命令

    bee version ===》 查看bee工具版本信息。
    bee new 项目名 ===》 创建一个beego项目。
    bee api 项目名 ===》 创建一个beego专做api的项目。
    bee run ===》 热编译,自动运行go文件中的 main函数。

    1. 项目配置

    beego 默认会解析当前应用下的 conf/app.conf 文件。
    通过这个文件你可以初始化很多 beego 的默认参数:

    常用配置项

    appname = drugDataCollect
    httpaddr = "127.0.0.1"
    httpport = 6666
    
    autorender = false
    copyrequestbody = true
    
    runmode = dev
    
    [dev]
    mysqluser = "root"
    mysqlpassword = "123456"
    mysqlurls = "127.0.0.1"
    mysqldb   = "drug_store_data_collect"
    
    redisaddr = "127.0.0.1"
    redisport = "6379"
    redispassword = ""
    redisdb = 1
    
    [prod]
    mysqluser = "root"
    mysqlpassword = "123456"
    mysqlurls = "127.0.0.1"
    mysqldb   = "drug_store_data_collect"
    
    [test]
    mysqluser = "root123test"
    mysqlpassword = "123456"
    mysqlurls = "127.0.0.1"
    mysqldb   = "gin"
    

    使用 配置文件 中的数据

    beego.AppConfig.String("mysqluser")
    beego.AppConfig.Int("redisdb")
    

    打包说明

    • step1 生产环境

    首先把conf/app.conf文件修改为 运行环境 prod

    • step2 项目打包

    方式一: 使用bee工具

    • 打包到Linux系统中使用
    bee pack -be GOOS=linux 
    
    • 打包到window系统中使用
    bee pack -be GOOS=windows
    

    然后将打包好的压缩包 传至服务器中 解压运行。

    • 方式二: 使用go命令
    go build 
    

    将生成的可执行文件 连同 项目配置文件conf 以及一些静态资源文件,一同上传到服务器中,运行可执行文件。

    2. 路由

    根路由必须以 ‘/’ 开头。

    单路由

    适合的路由处理风格: 一个url、一个结构体、多个请求方法

    beego.Router("/api/pharmacy", &controllers.Pharmacy{})
    beego.Router("/api/upfile", &controllers.UpLoadFile{})
    beego.Router("/api/cash_machine", &controllers.Cash{})
    

    路由组

    适合的路由处理风格: 多个url、一个结构体、一个请求方法

    // 通过 NewNamespace 创建路由组
    user := beego.NewNamespace("/user",
    	beego.NSRouter("login", &controllers.User{}),
    	beego.NSRouter("register", &controllers.User{}),
    	beego.NSRouter("repassword", &controllers.User{}),
    )
    
    // 通过 NSNamespace 深层嵌套
    group := beego.NewNamespace("/a",
    	beego.NSNamespace("/bb",
    		beego.NSNamespace("/ccc",
    			beego.NSRouter("/dddd", &controllers.Aaa{})))
    )
    
    // 路由组 钩子
    group := beego.NewNamespace("/a",
        	// 可理解为:前置中间件,如果返回true则可以达到后面的路由,false 则拒绝访问后面的路由
    		beego.NSCond(func(ctx *context.Context) bool {
    			fmt.Println("NSCond")
    			return true
    		}),
    
    		//NSCond 之后的钩子
    		beego.NSBefore(func(ctx *context.Context) {
    			fmt.Println("NSBefore")
    		}),
    
    	    beego.NSRouter("/dddd", &controllers.Aaa{})
    )
    
    // 所有的 路由组信息 都要在这里 进行注册
    beego.AddNamespace(user,group)
    

    指定路由

    beego.Router("/aaa", &controllers.Wtt{}, "get:Abc")
    

    get的方式访问/aaa路由,对应的处理函数 不再是Wtt上的Get方法,而是被指定为Wtt上的Abc方法。

    静态路由

    beego.SetStaticPath("imgs", "static") //imgs是访问的路径前缀,第二个是工程目录下的静态文件目录
    

    例如: 在工程目录下的静态文件static中有一个有一个aaa文件夹,aaa文件有一个abc.jpg的图片,那个这个图片的访问路径是:/imgs/aaa/abc.png

    广角路由

    package main
    
    import (
    	"fmt"
    	"github.com/beego/beego/v2/server/web/context"
    	beego "github.com/beego/beego/v2/server/web"
    )
    func Test(ctx *context.Context) {
    	fmt.Println("我是 中间件")
    	ctx.Output.Body([]byte{'o', 'k'})
    }
    
    func main() {
    	beego.Any("*", Test) // 广角路由
    	beego.Run("localhost:8088")
    }
    
    • 如果 命中了路由表中的路由,则执行指定的 controller
    • 如果没有命中 路由表中的路由,就执行广角路由。
    • 这里使用的是beego 2版本

    自动路由

    beego.AutoRouter(&Test{}) 
    
    type Test struct {
    	beego.Controller
    }
    
    //访问路径: /test/abc  请求方法:any
    func (that Test) Abc() { 
    	that.Ctx.Output.JSON(123, false, false)
    }
    

    3. 中间件

    Filter(中间件)

    • 引入beego 的 content包
      中间件 在 beego中 叫 过滤器 函数
      值得注意的是:
      每个中间件都一个content类型的参数,一定要手动引入该包
      “github.com/astaxie/beego/context”
      如果通过 保存操作 自动引入的话,会引入官方的 content包,
      因为 go 官方 的content的包 优先 第三方的 content 的包的引入。
    • 注册中间件 的 三个参数
      所有的 中间件 都要放到 InsertFilter 函数中,其有三个参数:

    参1: 中间件守卫的路由
    参2: 决定中间件执行的时机
    五个固定实参如下,分别表示不同的执行过程:
    beego.BeforeStatic ==》静态地址之前
    beego.BeforeRouter ==》寻找路由之前
    beego.BeforeExec ==》找到动态路由之后,开始执行相应的 Controller 之前
    beego.AfterExec ==》执行完 Controller 逻辑之后执行的过滤器
    beego.FinishRouter ==》执行完所有逻辑之后执行的过滤
    参3: 指定让哪个中间件工作

    • 执行顺序
      多个中间件守卫一个路由,其执行顺序:
      先由InsertFilter函数的的第二个参数决定,
      如果第二个参数一直 则 由于 InsertFilter函数的 先后顺序 决定:
      beego.InsertFilter("/aaa",beego.BeforeRouter, 中间件1)
      beego.InsertFilter("/aaa",beego.BeforeRouter, 中间件2)

    注意: 如果 任何一个 过滤器 中有向前端 返回数据 的动作, 则该 过滤器函数 执行周期之后的 过滤器函数 就不再执行了。

    import (
    	"fmt"
    	"github.com/astaxie/beego/context"
    )
    
    func Test(ctx *context.Context) {
    	fmt.Println("我是 中间件")
    }
    func Test111(ctx *context.Context) {
    	fmt.Println("我是 中间件111")
    }
    
    beego.InsertFilter("/test", beego.BeforeRouter, Test)
    beego.InsertFilter("/test", beego.BeforeRouter, Test111)
    // 正则路由
    beego.InsertFilter("/*", beego.BeforeRouter, Test) // 所有请求
    beego.InsertFilter("/user([0-9]+)", beego.BeforeRouter, Test) // ()里面中写入正则
    

    中间件间、中间件和路由处理函数间 传值

    // 路由表
    {
        beego.Router("/a", &Test{}, "post:Post1")
        beego.InsertFilter("/*", beego.BeforeRouter, m)
        beego.InsertFilter("/*", beego.BeforeRouter, m2)
    }
    // 中间件
    {
        // 中间件
        func m(ctx *context.Context) {
            // 设置 要传值的值
            ctx.Input.SetData("key", "value")
    
        	fmt.Println("我是 中间件")
        }
    
        // 中间件2
        func m2(ctx *context.Context) {
            // 获取 传值的值
    	    res := ctx.Input.GetData("key")
            // 设置 要传值的值
            ctx.Input.SetData("key", "value123")
    
        	fmt.Println("我是 中间件2")
        }
    }
    // 路由处理函数
    {
        type Test struct {
    	    beego.Controller
        }
    
        func (that Test) Post1() {
            // 获取 传值的值
        	res := that.Ctx.Input.GetData("key")
        	fmt.Println(res)
    
        	that.Ctx.Output.JSON(res, false, false)
        }
    }
    
    // 输出:
    value
    value123
    

    FilterChain(中间件回流)

    // 路由表
    {
        beego.InsertFilter("/*", beego.BeforeRouter, m)
        beego.InsertFilter("/*", beego.BeforeRouter, m2)
    
        // 不论 对 前端是否有回复 动作,都可以回到这里
        beego.InsertFilterChain("/*", func(next beego.FilterFunc) beego.FilterFunc {
        	return func(ctx *context.Context) {
        		fmt.Println(1111111111)
        		next(ctx)
        		fmt.Println(2222222222222)
        	}
        })
    }
    // 中间件
    {
        // 中间件
        func m(ctx *context.Context) {
        	fmt.Println("我是 中间件")
        }
    
        // 中间件2
        func m2(ctx *context.Context) {
        	fmt.Println("我是 中间件2")
        }
    }
    
    // 输出:
    /*
        1111111111
        我是 中间件
        我是 中间件2
        2222222222222
    */
    

    允许跨域中间件

    package main
    
    import (
    	beego "github.com/beego/beego/v2/server/web"
    	"github.com/beego/beego/v2/server/web/filter/cors"
    )
    
    func init() {
    	//InsertFilter是提供一个过滤函数
    	beego.InsertFilter("*", beego.BeforeRouter, cors.Allow(&cors.Options{
    		// 允许访问所有源
    		AllowAllOrigins: true,
    		// 可选参数"GET", "POST", "PUT", "DELETE", "OPTIONS" (*为所有)
    		AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
    		// 指的是允许的Header的种类
    		AllowHeaders: []string{"Origin", "Authorization", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Content-Type"},
    		// 公开的HTTP标头列表
    		ExposeHeaders: []string{"Content-Length", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "Content-Type"},
    		// 如果设置,则允许共享身份验证凭据,例如cookie
    		AllowCredentials: true,
    	}))
    }
    
    

    4. 控制器

    对于每个请求,beego 都会采用单独的 goroutine 来处理
    基于 beego 的 Controller 结构体 设计,只需要匿名组合 beego.Controller 就可以了

    package controllers
    
    import (
    	"drugDataCollect/models"
    	"drugDataCollect/tools"
    	"encoding/json"
    	"fmt"
    	"time"
    
    	"github.com/astaxie/beego"
    )
    
    type User struct {
    	beego.Controller
    }
    
    func (that User) Post() {
    	switch that.Ctx.Input.URL() {
    	case "/user/login":
    		that.Login()
    	case "/user/register":
    		that.Register()
    	case "/user/repassword":
    		that.Repassword()
    	default:
    		return
    	}
    
    }
    
    func (that User) Login() {
    	// var m map[string]interface{} 用map也可以,但是语义性不强。
    	reqObj := struct {
    		Account  string
    		Password string
    	}{}
    
    	err := json.Unmarshal(that.Ctx.Input.RequestBody, &reqObj)
    	if err != nil {
    		fmt.Println(err)
    	}
    	// fmt.Println(m.Account)
    
    	userData := models.Users{}
    	tools.DB.Where("account=?", reqObj.Account).First(&userData)
    	// fmt.Printf("%T >>---> %+v\n", userData, userData)
    
    	if len(userData.Password) == 0 {
    		tools.Failed(that.Ctx, "该账号未注册")
    	} else {
    		if userData.Password != reqObj.Password {
    			tools.Failed(that.Ctx, "密码不正确")
    		} else {
    			jwt, err := tools.GetToken(userData.Account, userData.Password)
    			if err != nil {
    				fmt.Println(err)
    			}
    			conn := tools.Pool.Get()
    			defer conn.Close()
    			_, err = conn.Do("set", userData.Account, userData.Password)
    			if err != nil {
    				fmt.Println(err)
    			}
    
    			resData := struct {
    				Username string `json:"username"`
    				AreaId   int    `json:"areaid"`
    				Area     string `json:"area"`
    				Token    string `json:"token"`
    			}{}
    
    			resData.Username = userData.Username
    			resData.AreaId = userData.AreaId
    			resData.Area = userData.Area
    			resData.Token = jwt
    
    			tools.Success(that.Ctx, resData)
    		}
    	}
    	return
    }
    func (that User) Register() {
    	reqObj := struct {
    		Account   string
    		Password  string
    		Username  string
    		AreaId    int
    		Area      string
    		AreaRange string
    	}{}
    	err := json.Unmarshal(that.Ctx.Input.RequestBody, &reqObj)
    	if err != nil {
    		fmt.Println(err)
    	}
    
    	// 基础的 表单验证 在前段进行验证, 后端只需要整 Account 是否 有重名
    	userData := models.Users{}
    	tools.DB.Where("account=?", reqObj.Account).First(&userData)
    	if len(userData.Password) != 0 {
    		tools.Failed(that.Ctx, "该账号已被注册,请更换")
    		return
    	}
    
    	userData.Account = reqObj.Account
    	userData.Password = reqObj.Password
    	userData.Username = reqObj.Username
    	userData.AreaId = reqObj.AreaId
    	userData.Area = reqObj.Area
    	userData.AreaRange = reqObj.AreaRange
    
    	timeStr := time.Now().Format("2006-01-02 15:04:05")
    
    	userData.RewordTime = timeStr
    	userData.LoginTime = timeStr
    	userData.RegistryTime = timeStr
    
    	tools.DB.Create(&userData)
    	tools.Success(that.Ctx, "注册成功")
    }
    func (that User) Repassword() {
    	reqObj := struct {
    		NewPassword string
    		Token       string
    	}{}
    	err := json.Unmarshal(that.Ctx.Input.RequestBody, &reqObj)
    	if err != nil {
    		fmt.Println(err)
    	}
    	// 验证密码长短 在前端搞定
    
    	_, msg, err := tools.ParseToken(reqObj.Token)
    	// 验证token的真实性
    	if msg.StandardClaims.Subject == "wtt" {
    		tools.DB.Debug().Table("users").Where("account = ?", msg.Username).Update("password", reqObj.NewPassword)
    		tools.Success(that.Ctx, "密码修改成功")
    	}
    }
    
    

    控制器结构体上的方法

    钩子

    • Prepare()

    这个函数会在 这些 Method 方法之前执行,用户可以重写(重写:在继承的结构体上 重名覆盖这个方法)这个函数实现类似用户验证之类。

    • Finish()

    这个函数是在执行完相应的 HTTP Method 方法之后执行的,默认是空,用户可以在子 struct 中重写这个函数,执行例如数据库关闭,清理数据之类的工作

    请求方法

    • Get()

    如果用户请求的 HTTP Method 是 GET,那么就执行该函数,默认是 405,用户继承的子 struct 中可以实现了该方法以处理 Get 请求。

    • Post()

    如果用户请求的 HTTP Method 是 POST,那么就执行该函数,默认是 405,用户继承的子 struct 中可以实现了该方法以处理 Post 请求。

    • Delete()

    如果用户请求的 HTTP Method 是 DELETE,那么就执行该函数,默认是 405,用户继承的子 struct 中可以实现了该方法以处理 Delete 请求。

    • Put()

    如果用户请求的 HTTP Method 是 PUT,那么就执行该函数,默认是 405,用户继承的子 struct 中可以实现了该方法以处理 Put 请求.

    • 其他: Head()、Patch()、Options()、Finish()、Trace()

    操控处理

    • Redirect(url string, code int)

    重定向。url是目的地址。

    • Abort(code string)

    中断当前方法的执行,直接返回该状态码,类似于CustomAbort。

    报文

    • 请求报文: Ctx.Input
    • 响应报文: Ctx.Output

    5. 前后交互

    • context 对象 是对 InputOutput 的封装,
    • context 对象 是 中间件函数 唯一的 参数对象,这样你就可以通过 中间件 来修改相应的数据,或者提前结束整个的执行过程。

    请求报文

    Input 对象是针对 request(请求报文) 的封装,里面实现很多方便的方法,具体如下:

    协议、域名、

    • Input.Protocol()

    获取用户请求的协议,例如 HTTP/1.1

    • Scheme()

    请求的 scheme,例如 “http” 或者 “https”

    • Domain()

    请求的域名,例如 beego.me

    • Port()

    返回请求的端口,例如返回 8080

    • Input.URL()

    请求的 URL 地址,例如 /hi


    • IP()

    返回请求用户的 IP,如果用户通过代理,一层一层剥离获取真实的 IP

    • Proxy()

    返回用户代理请求的所有 IP

    • UserAgent()

    返回请求的 UserAgent,例如 Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36


    • IsSecure()

    判断当前请求是否 HTTPS 请求,是返回 true,否返回 false

    • IsWebsocket()

    判断当前请求是否 Websocket 请求,如果是返回 true,否返回 false

    • IsAjax()

    判断是否是 AJAX 请求,如果是返回 true,不是返回 false

    获取数据

    Get方法 的 请求参数

    • Param()

    获取那些在路由上 早早定义好 的参数:

    // 路由
    beego.Router("/aaa/bbb/:name", &controllers.MainController{})
    
    // url: http://localhost/aaa/bbb/tom
    
    // 控制器
    res := c.Ctx.Input.Param(":name") // tom
    
    • Query()

    获取Get方法的请求参数: http://localhost/aaa/bbb?name=tom

    Post、Put 的 请求体

    • RequestBody

    解析 请求体为 json 和 xml 格式的数据
    在配置文件里设置 copyrequestbody = true , 否则 RequestBody 拿不到数据

    // var m map[string]interface{} 用map也可以,但是语义性不强。
    reqObj := struct {
    	Account  string
    	Password string
    }{}
    err := json.Unmarshal(that.Ctx.Input.RequestBody, &reqObj)
    if err != nil {
    	fmt.Println(err)
    }
    fmt.Println(reqObj)
    
    • ParseForm

    解析 请求体为 form-data 和 x-www-form-urlencode 格式的数据

    type user struct {
    	Id    int         `form:"-"`        // 忽略Id字段(一:字段名小写开头,二:form 标签的值设置为 -)
    	Name  interface{} `form:"username"` // 只接受 username 字段
    	Age   int         `form:"age"`      // 只接受 age 字段
    	Email string      // 只接受 Email 字段
    }
    u := user{}
    // 解析请求体为 form-data 和 x-www-form-urlencode 格式的数据
    err := that.ParseForm(&u)
    if err != nil {
    	fmt.Println(err)
    }
    

    其他重点

    • GetString(“name”)、GetInt(key string)、GetBool(key string)、GetFloat(key string)

    获取:
    post:form-datax-www-form-urlencode
    get:?之后的参数
    注意:此方法无法获取 post的json格式的数据

    • Header()

    返回相应的 header 信息,例如 Header(“Accept-Language”)

    • Cookie()

    返回请求中的 cookie 数据,例如 Cookie(“username”),就可以获取请求头中携带的 cookie 信息中 username 对应的值

    文件传输

    • beego.BConfig.MaxMemory= 123 (文件 缓存内存)

    文件上传之后一般是放在系统的内存里面,
    如果文件的 size 大于设置的缓存内存大小,那么就放在 临时文件 中,
    默认的缓存内存是 64M,可以通过在配置文件中通过如下设置:

    maxmemory = 1<<22
    相应的也可以在代码中如下设置:

    // 单位B
    beego.BConfig.MaxMemory = 123
    
    • beego.BConfig.MaxUploadSize = 234 (限制最大上传文件大小)
    // 单位B, 4530 B == 4.5 K
    beego.BConfig.MaxUploadSize = 4530
    

    与此同时,beego 提供了另外一个参数,MaxUploadSize来限制最大上传文件大小——如果你一次长传多个文件,那么它限制的就是这些所有文件合并在一起的大小。
    默认情况下,MaxMemory应该设置得比MaxUploadSize小,这种情况下两个参数合并在一起的效果则是:

    1. 如果文件大小小于MaxMemory,则直接在内存中处理;
    2. 如果文件大小介于MaxMemory和MaxUploadSize之间,那么比MaxMemory大的部分将会放在临时目录;
    3. 文件大小超出MaxUploadSize,直接拒绝请求,返回响应码 413
    • IsUpload()

    判断当前请求是否有文件上传,有返回 true,否返回 false
    实质上是判断接收的数据是否是 form-data 类型的,如果是,哪怕是文字数据也返回true。

    • GetFile() 和 SaveToFile()

    获取**form-data** 类型的 文件数据

    func (that UpLoadFile) Post() {
    	f, h, err := that.GetFile("filename")
    	id := that.GetString("id")
    	name := that.GetString("name")
    
    	if err != nil {
    		fmt.Println(err)
    		tools.Failed(that.Ctx, "文件获取失败")
    		return
    	}
    	defer f.Close()
    
        // 文件名
        fmt.Println(h.Filename)
        // 文件大小,单位B, h.Size / 1024 = KB
    	fmt.Println(h.Size)
    
    	uuid := uuid.New() // uuid(32位的随机 数组or字母)是文件名不重复的一个保证
    	// 该路径上的涉及到的 文件夹 提前创建好
    	var path string = "static/upload/" + id + "-" + name + "-" + uuid + h.Filename
    	
        // 该方法是在 GetFile 的基础上实现了快速保存的功能
        err = that.SaveToFile("filename", path)
    	if err != nil {
    		fmt.Println(err)
    		tools.Failed(that.Ctx, "文件上传失败")
    	} else {
    		// 将 静态路由 返回给 前端
    		tools.Success(that.Ctx, path)
    	}
    	return
    }
    
    • 多文件上传
    // 多文件上传
    func (that File) UploadFiles() {
    	resM := make(map[string]string, 10)
    	// this is core
    	allUpFiles := that.Ctx.Request.MultipartForm.File
    
    	for k, _ := range allUpFiles {
    		res := upload(that, k)
    		resM[k] = res
    	}
    	tools.Failed(that.Ctx, resM)
    }
    
    func upload(that File, filename string) string {
    	f, h, err := that.GetFile(filename)
    	if err != nil {
    		tools.Failed(that.Ctx, "文件获取失败")
    		return ""
    	}
    	defer f.Close()
    
    	uuid := uuid.New()
    
    	var path string = "static/upload/" + uuid + h.Filename
    	err = that.SaveToFile(filename, path)
    
    	if err != nil {
    		fmt.Println(err)
    		tools.Failed(that.Ctx, "文件上传失败")
    	}
    	ddr, err := beego.AppConfig.String("httpaddr")
    	if err != nil {
    		panic("配置文件中 httpaddr 字段提取异常")
    	}
    	port, err := beego.AppConfig.String("httpport")
    	if err != nil {
    		panic("配置文件中 httpport 字段提取异常")
    	}
    	path = ddr + ":" + port + "/" + path
    	return path
    }
    
    

    响应报文

    Output 是针对 Response(响应报文) 的封装,里面提供了很多方便的方法:

    • Body() => Ctx.Output.Body([]byte(“see you”))

    将 参数数据 放到响应体中,并返回给前端

    • JSON() => Ctx.Output.JSON(map或struct, false, false)

    把 Data 格式化为 Json,然后调用 Body() 输出数据到前端

    • Header()

    设置输出的 header 信息,例如 Header(“Server”,“beego”)

    • Cookie()

    将cookie写入到前端浏览器中,例如 Cookie(“name”,“tom”)

    6. 数据模型

    请转到我的GORM那一篇。

    7. 会话管理

    Cookie

    • 设置: Ctx.Output.Cookie(“name”, “tom123”, 1) //参数3的单位:分钟
    • 获取: Ctx.Input.Cookie(“name”)
    • 删除: Ctx.Output.Cookie(“name”, “tom123”, -1)

    Session

    这里用 token + cookie 的顶替 session,
    session的不足:

    1. CSRF跨站伪造请求攻击session是基于cookie进行用户识别的, cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击
    2. 扩展性不强,如果将来搭建了多个服务器,虽然每个服务器都执行的是同样的业务逻辑,但是session数据是保存在内存中的(不是共享的),用户第一次访问的是服务器1,当用户再次请求时可能访问的是另外一台服务器2,服务器2获取不到session信息,就判定用户没有登陆过。

    8. 日志记录

    step1: 启用日志

    在main函数中写入: log.UseLog()

    step2: 创建日志实例 及 相关配置

    package log
    
    import "github.com/astaxie/beego/logs"
    
    func UseLog() {
    	log := logs.NewLogger(10000) // 创建一个日志实例,参数为缓冲区的大小
    	defer log.Close()
    
    	// 设置配置文件
    	// filename 文件名(不指定路径,就生成在主目录); maxlines 最大行; maxsize 最大Size;
    	jsonConfig := `{
            "filename" : "test.log",
            "maxlines" : 1000,      
            "maxsize"  : 10240      
        }`
    	log.SetLogger("file", jsonConfig) // 设置日志记录方式!!!:本地文件记录
    	log.SetLevel(logs.LevelDebug)     // 设置可以 写入 日志 的 错误的 等级
    	log.EnableFuncCallDepth(true)     // 输出log时能显示输出文件名和行号(非必须)
    
    	// 通过主动让代码 触发 一些有等级的错误 ,已方便测试 test.log 对错误 的记录
    	log.Emergency("Emergency")
    	log.Alert("Alert")
    	log.Critical("Critical")
    	log.Error("Error")
    	log.Warning("Warning")
    	log.Notice("Notice")
    	log.Informational("Informational")
    	log.Debug("Debug")
    
    	log.Flush() // 将日志从缓冲区读出,写入到文件
    
    }
    
    /*
    log.SetLogger 是 设置日志记录方式:
    beego框架之日志模块默认支持4种记录方式:
      1. 终端输出(console) :这种方式一般用在开发环境下面,方便调试。
      2. 本地文件(file)       :这种方式一般用来保存常规日志,为生产环境中常用的方式。
      3. 网络方式(network):这种方式可以用来将日志发送到指定服务器,一般可以用来根据日志触发事件等。
      4. 发送邮件(email)   :这种方式一般是将生产环境下比较重要的日志发送给相应的管理人员,以便及时发现和解决问题。
    
    
    
    log.SetLevel 是 设置 可以被记录的错误的 等级的:
    beego框架之日志模块等级定义在github.com/astaxie/beego/logs/log.go:(级别以此递减)
      const (
        LevelEmergency = iota // 紧急级别
        LevelAlert                   // 报警级别
        LevelCritical                // 严重错误级别
        LevelError                   // 错误级别
        LevelWarning              // 警告级别
        LevelNotice                 // 注意级别
        LevelInformational       // 报告级别
        LevelDebug                 // 除错级别
      )
    */
    
    

    9. 错误处理

    在做 Web 开发的时候,经常需要页面跳转和错误处理,beego 这方面也进行了考虑,
    通过 控制器 上的 RedirectAbort 方法来进行 跳转 或 中断。

    10. 安全防护

    • XSRF攻击
      跨站请求伪造(Cross-site request forgery), 是 Web 应用中常见的一个安全问题。
      防御策略: 当前防范 XSRF 的一种通用的方法,是对每一个用户都记录一个无法预知的 cookie 数据,然后要求所有提交的请求(POST/PUT/DELETE)中都必须带有这个 cookie 数据。如果此数据不匹配 ,那么这个请求就可能是被伪造的。

    11. 常备工具

    Mysql

    package tools
    
    import (
    	"os"
    
    	"github.com/astaxie/beego"
    	"github.com/fatih/color"
    	"github.com/jinzhu/gorm"
    	_ "github.com/jinzhu/gorm/dialects/mysql"
    )
    
    //DB 数据库变量
    var DB *gorm.DB
    
    //DBinit 初始化数据库
    func DBinit() *gorm.DB {
    
    	arr1 := "mysql"
    	arr2 := beego.AppConfig.String("mysqluser") +
    		":" + beego.AppConfig.String("mysqlpassword") +
    		"@(" + beego.AppConfig.String("mysqlurls") + ")/" +
    		beego.AppConfig.String("mysqldb") +
    		"?charset=utf8mb4&parseTime=True&loc=Local"
    
    	// var arr3 string = "root:123456@(127.0.0.1)/drug_store_data_collect?charset=utf8mb4&parseTime=True&loc=Local"
    
    	db, err := gorm.Open(arr1, arr2)
    
    	if err != nil {
    		color.Red("连接数据库失败", err)
    		os.Exit(3)
    	} else {
    		d := color.New(color.FgCyan, color.Bold)
    		d.Printf("mysql 连接成功 \n")
    	}
    	db.SingularTable(true) // 不允许给 表名 加复数形式
    
    	DB = db
    	return db
    }
    

    Redis

    package tools
    
    import (
    	"time"
    
    	"github.com/astaxie/beego"
    	"github.com/garyburd/redigo/redis"
    )
    
    var Pool *redis.Pool
    
    func RedisInit() {
    	// 连接池
    	Pool = &redis.Pool{
    		//最大闲置连接数
    		MaxIdle: 20,
    
    		//最大活动连接数, 0==无穷
    		MaxActive: 1000,
    
    		//闲置连接的超时时间 (如果开辟的IO 100秒之内什么都不干,就断定为闲置)
    		IdleTimeout: time.Second * 100,
    
    		//定义获得连接的 函数
    		Dial: func() (redis.Conn, error) {
    			// return redis.Dial("tcp", "127.0.0.1:6379", redis.DialDatabase(1)) // 没有密码的情况
    			// return redis.Dial("tcp", "127.0.0.1:6379", redis.DialPassword("123456"), redis.DialDatabase(1)) // 有密码的情况
    
    			protocol := "tcp"
    			url := beego.AppConfig.String("redisaddr") + ":" + beego.AppConfig.String("redisport")
    			dbIndex, _ := beego.AppConfig.Int("redisdb")
    			return redis.Dial(protocol, url, redis.DialDatabase(dbIndex))
    		},
    	}
    	// defer Pool.Close() // 注意: 连接池要一直开着,关闭了 就从里面取不出 io了,就是去了 连接池的意义了。
    
    }
    // 使用的时候 直接 从池中 取出一个 IO
    // 	conn := Pool.Get()
    // 	defer conn.Close()
    // conn.Do("set", arr1, arr2)
    

    Token

    package tools
    
    import (
    	"time"
    
    	"github.com/dgrijalva/jwt-go"
    )
    
    var jwtKey = []byte("wtt")
    
    //Claims token结构体
    type Claims struct {
    	Username string `json:"username"`
    	Password string `json:"password"`
    	jwt.StandardClaims
    }
    
    //GetToken 产生token 给前端
    func GetToken(username, password string) (string, error) {
    	expireTime := time.Now().Add(1 * time.Hour) // 有效时间一个小时
    	claims := &Claims{
    		Username: username,
    		Password: password,
    		StandardClaims: jwt.StandardClaims{
    			ExpiresAt: expireTime.Unix(),
    			IssuedAt:  time.Now().Unix(),
    			Issuer:    "GoGin",
    			Subject:   "wtt",
    		},
    	}
    	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    	tokenString, err := token.SignedString(jwtKey)
    	return tokenString, err
    }
    
    //ParseToken 解析前端传过来的 token
    func ParseToken(tokenString string) (*jwt.Token, *Claims, error) {
    	claims := &Claims{}
    
    	arr1 := tokenString
    	arr2 := claims
    	arr3 := func(token *jwt.Token) (i interface{}, err error) {
    		return jwtKey, nil
    	}
    	token, err := jwt.ParseWithClaims(arr1, arr2, arr3)
    	return token, claims, err
    }
    

    图形验证

    package tools
    
    import (
    	"fmt"
    	"image/color"
    
    	"github.com/astaxie/beego/context"
    	"github.com/garyburd/redigo/redis"
    	"github.com/mojocn/base64Captcha"
    )
    
    type CaptchaResult struct {
    	Id          string `json:"id"`
    	Base64Blob  string `json:"base_64_blob"`
    	VerifyValue string `json:"code"`
    }
    
    // 配置验证码信息
    var captchaConfig = base64Captcha.DriverString{
    	Height:          50,
    	Width:           100,
    	NoiseCount:      0,
    	ShowLineOptions: 0 | 2,
    	Length:          4,
    	Source:          "123456879qwertyuiopasdfghlzxcvbnm",
    	BgColor: &color.RGBA{
    		R: 3,
    		G: 102,
    		B: 214,
    		A: 125,
    	},
    	Fonts: []string{"wqy-microhei.ttc"},
    }
    
    // 自定义配置,如果不需要自定义配置,则上面的结构体和下面这行代码不用写
    var driverString base64Captcha.DriverString = captchaConfig
    
    var driver base64Captcha.Driver = driverString.ConvertFonts()
    
    // 这是自带的 store,存储数据的结构是变量
    // var store = base64Captcha.DefaultMemStore
    // 但是官方推荐 store 的存储数据的结构最好是redis,其有数据持久化的功能。
    type RedisStore struct {
    	Conn redis.Conn
    }
    
    func (that *RedisStore) Set(id, value string) {
    
    	_, err := that.Conn.Do("set", id, value)
    
    	if err != nil {
    		fmt.Println(err)
    	} else {
    		fmt.Println("redis set success")
    	}
    }
    
    func (that *RedisStore) Get(id string, clear bool) string {
    	val, err := redis.String(that.Conn.Do("get", id))
    	if err != nil {
    		fmt.Println(err)
    	} else {
    		fmt.Println("redis get success")
    	}
    	if clear {
    		that.Conn.Do("del", id)
    	}
    	return val
    }
    
    func (that *RedisStore) Verify(id, answer string, clear bool) bool {
    	val := that.Get(id, clear)
    	return val == answer
    }
    
    // 生成图形化验证码
    func GenerateCaptcha(ctx *context.Context) (CaptchaResult, error) {
    
    	var conn = Pool.Get()
    	defer conn.Close()
    
    	var store = &RedisStore{conn}
    
    	// 驱动 + 仓库  =》验证码实例
    	var captcha = base64Captcha.NewCaptcha(driver, store)
    
    	// 验证码实例 =》产生一个 验证码
    	id, b64s, err := captcha.Generate()
    	if err != nil {
    		return CaptchaResult{}, err
    	}
    	return CaptchaResult{
    		Id:         id,
    		Base64Blob: b64s,
    	}, nil
    }
    
    // 验证 前端 发过来的 验证码 是否正确
    func CheckCaptcha(id, data string) bool {
    	var conn = Pool.Get()
    	defer conn.Close()
    
    	var store = &RedisStore{conn}
    
    	// 驱动 + 仓库  =》验证码实例
    	var captcha = base64Captcha.NewCaptcha(driver, store)
    
    	res := captcha.Verify(id, data, true)
    	return res
    }
    

    统一返回数据格式

    package tools
    
    import (
    	"fmt"
    
    	"github.com/astaxie/beego/context"
    )
    
    type Status int
    
    func (that Status) String() {
    	switch that {
    	case 0:
    		fmt.Println("该状态为 操作成功")
    	case 1:
    		fmt.Println("该状态为 操作失败")
    	}
    }
    
    //SUCCESS FAILED 枚举
    const (
    	SUCCESS Status = 0 // 操作成功
    	FAILED  Status = 1 //操作失败
    )
    
    //Success 成功 de 返回
    func Success(ctx *context.Context, v interface{}) {
    	res := map[string]interface{}{
    		"code": SUCCESS,
    		"data": v,
    	}
    	ctx.Output.JSON(res, false, false)
    }
    
    //Failed 失败 de 返回
    func Failed(ctx *context.Context, v interface{}) {
    	res := map[string]interface{}{
    		"code": FAILED,
    		"msg":  v,
    	}
    	ctx.Output.JSON(res, false, false)
    }
    

    分页

    package tools
    
    //Page is
    type Page struct {
    	CurrentPage int         `json:"currentPage"` //当前页
    	PageSize    int         `json:"pageSize"`    // 一页个数
    	TotalPage   int         `json:"totalPage"`   // 总的页数
    	TotalCount  int         `json:"totalCount"`  //总的个数
    	FirstPage   bool        `json:"firstPage"`   //是否首页
    	LastPage    bool        `json:"lastPage"`    //是否尾页
    	Data        interface{} `json:"data"`        // 返回给前端的数据
    }
    
    //PageUtil  count 总的数据个数; currentpage 当前页; pageSize 一页显示的个数
    func PageUtil(count int, currentpage int, pageSize int, Data interface{}) Page {
    	tp := count / pageSize
    	if count%pageSize > 0 {
    		tp = count/pageSize + 1
    	}
    	return Page{
    		CurrentPage: currentpage,
    		PageSize:    pageSize,
    		TotalPage:   tp,
    		TotalCount:  count,
    		FirstPage:   currentpage == 1,
    		LastPage:    currentpage == tp,
    		Data:        Data,
    	}
    }
    

    12. 应用部署

    Nginx部署

    Go 是一个独立的 HTTP 服务器,但是我们有些时候为了 nginx 可以帮我做很多工作,例如访问日志,cc 攻击,静态服务等,nginx 已经做的很成熟了,Go 只要专注于业务逻辑和功能就好,所以通过 nginx 配置代理就可以实现多应用同时部署,如下就是典型的两个应用共享 80 端口,通过不同的域名访问,反向代理到不同的应用。

    server {
        listen       80;
        server_name  .a.com;
    
        charset utf-8;
        access_log  /home/a.com.access.log;
    
        location /(css|js|fonts|img)/ {
            access_log off;
            expires 1d;
    
            root "/path/to/app_a/static";
            try_files $uri @backend;
        }
    
        location / {
            try_files /_not_exists_ @backend;
        }
    
        location @backend {
            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_set_header Host            $http_host;
    
            proxy_pass http://127.0.0.1:8080;
        }
    }
    
    server {
        listen       80;
        server_name  .b.com;
    
        charset utf-8;
        access_log  /home/b.com.access.log  main;
    
        location /(css|js|fonts|img)/ {
            access_log off;
            expires 1d;
    
            root "/path/to/app_b/static";
            try_files $uri @backend;
        }
    
        location / {
            try_files /_not_exists_ @backend;
        }
    
        location @backend {
            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_set_header Host            $http_host;
    
            proxy_pass http://127.0.0.1:8081;
        }
    }
    

    Apache部署

    NameVirtualHost *:80
    <VirtualHost *:80>
        ServerAdmin webmaster@dummy-host.example.com
        ServerName www.a.com
        ProxyRequests Off
        <Proxy *>
            Order deny,allow
            Allow from all
        </Proxy>
        ProxyPass / http://127.0.0.1:8080/
        ProxyPassReverse / http://127.0.0.1:8080/
    </VirtualHost>
    
    <VirtualHost *:80>
        ServerAdmin webmaster@dummy-host.example.com
        ServerName www.b.com
        ProxyRequests Off
        <Proxy *>
            Order deny,allow
            Allow from all
        </Proxy>
        ProxyPass / http://127.0.0.1:8081/
        ProxyPassReverse / http://127.0.0.1:8081/
    </VirtualHost>
    

    13. 升级协议

    websocket协议

    通过github.com/gorilla/websocket可以在beego中使用websocket协议:

    package main
    
    import (
    	"fmt"
    	"net/http"
    
    	// "github.com/astaxie/beego"  beego v1.x
    	beego "github.com/beego/beego/v2/server/web" // beego v2.x
    	"github.com/fatih/color"
    	"github.com/gorilla/websocket"
    )
    
    // 核心 协议升级结构体
    var upgrader = websocket.Upgrader{
    	ReadBufferSize:  1024,
    	WriteBufferSize: 1024,
    	// 允许跨域访问
    	CheckOrigin: func(r *http.Request) bool {
    		return true
    	},
    }
    
    type Ws struct {
    	beego.Controller
    }
    
    func (that *Ws) Get() {
    	conn, err := upgrader.Upgrade(that.Ctx.ResponseWriter, that.Ctx.Request, nil)
    	if err != nil {
    		fmt.Println(err)
    		color.Red("升级成功")
    	} else {
    		color.Red("升级成功")
    	}
    
    	for {
    		fmt.Println("开始循环----接受---- 客户端发过来的信息")
    		msgType, msg, err := conn.ReadMessage()
    		if err != nil {
    			fmt.Println(err)
    			break
    		}
    		fmt.Println("接收到客户端发过来的信息是:", msg)
    
    		msg = append(msg, 'w', 't', 't')
    		fmt.Println("----发送----到客户端的信息是:", string(msg))
    		err = conn.WriteMessage(msgType, msg)
    		if err != nil {
    			fmt.Println(err)
    			break
    		}
    	}
    }
    
    func main() {
    	// websocket 测试地址: ws://localhost:8081/wtt
    	beego.Router("/wtt", &Ws{})
    
    	beego.Run("localhost:8081")
    }
    

    https协议

    • 首先需要获得一个https的证书 (SSl证书),这个证书可以自己做,也可以到网站申请。
    • 如果是自己做的证书,浏览器访问的时候会提示不安全链接之类,建议还是自己申请。在腾讯云里有免费1年的CA证书可以申请,可以申请试用。
    • 获得CA证书后,如果是直接用beego作为http服务器,就需要设置beego的配置文件,配置如下:
    appname = rxw
    httpaddr = "0.0.0.0"
    httpport = 8080
    
    # 以下是https配置信息
    EnableHTTPS = true
    EnableHttpTLS = true
    HTTPSPort = 8010
    HTTPSCertFile = "server.crt"
    HTTPSKeyFile = "server.key"  
    
    autorender = false
    copyrequestbody = true
    runmode = prod
    
    

    说明:
    以上配置开启两个服务,监听两个端口,一个是http服务监听8080端口;另一个是https服务监听8010端口

    • 如果是使用Nginx,就可以直接通过nginx转发流量到Beego了。(注意:一般会有不同服务器的证书版本,若用nginx作为服务器,就使用Nginx版本的就可以了)

    自己生成SSL证书

    1. 生成服务器私钥
    # 键入以下命令:
    openssl genrsa -des3 -out server.key 1024
    
    # 反馈画面
    Generating RSA private key, 1024 bit long modulus
    .......................................++++++
    ..............................................++++++
    e is 65537 (0x10001)
    Enter pass phrase for server.key:
    Verifying - Enter pass phrase for server.key:
    

    设定一个密码(至少4位)并确认

    1. 生成服务器证书请求(csr)
      在生成csr文件的过程中,有一点很重要, Common Name 填入主机名(或者服务器IP)
    # 键入以下命令:
    openssl req -new -key server.key -out server.csr
    
    # 反馈画面
    Enter pass phrase for server.key:
    You are about to be asked to enter information that will be incorporated
    into your certificate request.
    What you are about to enter is what is called a Distinguished Name or a DN.
    There are quite a few fields but you can leave some blank
    For some fields there will be a default value,
    If you enter '.', the field will be left blank.
    -----
    Country Name (2 letter code) [AU]:CN
    State or Province Name (full name) [Some-State]:Shanghai
    Locality Name (eg, city) []:Shanghai
    Organization Name (eg, company) [Internet Widgits Pty Ltd]:AAA
    Organizational Unit Name (eg, section) []:OT               
    Common Name (e.g. server FQDN or YOUR name) []:127.0.0.1
    Email Address []:
    
    Please enter the following 'extra' attributes
    to be sent with your certificate request
    A challenge password []:
    An optional company name []:
    
    1. 删除私钥中密码
      在第一步创建私钥的过程中,由于必须制定一个密码,而这个密码的副作用是,每次启动http服务的时候,都会要求输入密码,这会带来很大的不变。可以通过以下方式删除私钥中密码
    # 键入以下两条命令:
    cp server.key server.key.org
    openssl rsa -in server.key.org -out server.key
    
    1. 生成服务器证书
      如果你不想花钱让ca签名,那么可以以下方式生成一个自签名的证书
    openssl x509 -req -days 3650 -in server.csr -signkey server.key -out  server.crt
    
    1. 查看证书内容信息
    openssl x509 -noout -text -in server.crt
    
    1. 操作成果
      在当前目录下得到以下文件:
    • server.key.org
    • server.key (待使用)
    • server.csr
    • server.crt (待使用)

    腾讯云后台申请

    • 我的证书
    • 申请免费证书
    • 绑定域名、输入邮箱、证书备注信息、私钥密码(至少6位数)
    • 之后按照上面步骤
    • 通过之后在我的证书中找到申请的证书,点击下载,得到以下文件
    ├── Apache
    │   ├── 1_root_bundle.crt
    │   ├── 2_wtt.ruixiaowan.com.crt
    │   └── 3_wtt.ruixiaowan.com.key
    ├── IIS
    │   └── wtt.ruixiaowan.com.pfx
    ├── Nginx
    │   ├── 1_wtt.ruixiaowan.com_bundle.crt (待使用)
    │   └── 2_wtt.ruixiaowan.com.key (待使用)
    ├── Tomcat
    │   └── wtt.ruixiaowan.com.jks
    ├── wtt.ruixiaowan.com.csr
    ├── wtt.ruixiaowan.com.key
    └── wtt.ruixiaowan.com.pem
    
    • 这里我们就使用nginx的服务器证书就可以了。
    展开全文
  • beego 错误拦截返回json

    2020-10-27 17:34:10
    beego 错误拦截返回json main 文件 func main() { ... //启动 beego.Run() } package utils import ( "fmt" "github.com/astaxie/beego" "github.com/astaxie/beego/context" "github.com/asta
  • 简介 BeeGo是一个快速开发Go而应用的HTTP框架,他可以用来快速开发API,web以及后端服务等各种应用,是一个restful 的框架,主要涉及灵感来源于tornado,sinatr和flask这三个框架,但是...beego有八个模块,分别是...
  • 启动beego程序前面加入这段即可 path, _ := exec.LookPath(os.Args[0]) fileFullPath, _ := filepath.Abs(path) relativePath := filepath.Dir(fileFullPath) staticPath := relativePath + "/static" beego....
  • beego框架源码解析:启动和监听过程,路由信息是怎么给到 webserver的 E:\workspace_go\pkg\mod\github.com\beego\beego\v2@v2.0.1\server\web\server.go func init() { // create beego application BeeApp = ...
  • beego配置文件路径如下: app.conf内容 httpaddr = "192.168.199.178" httpport = 9091 appname = SecProxy runmode = "${ProRunModel||dev}" autorender = false [dev] redis_addr = 192.168.199....
  • 一、Beego介绍与项目创建及启动

    千次阅读 2019-03-19 22:50:00
    一、beego 简介 beego 是一个快速开发 Go 应用的 HTTP 框架,他可以用来快速开发 API、Web 及后端服务等各种应用,是一个 RESTful 的框架,主要设计灵感来源于 tornado、sinatra 和 flask 这三个框架,但是结合了 ...
  • beego框架

    2018-11-09 18:16:23
    按照提示,在shell中下载安装beego go get github.com/astaxie/beego 安装bee工具 go get -u github.com/beego/bee 结果报错 sszxrmc:~ sszxr$ go get -u github.com/beego/bee # github.co...
  • 目录一、停止掉本机安装的mysql二、创建文件夹三、在conf文件夹下编写my.cnf数据库配置文件四、编写docker-compose五、启动docker六、进入docker...用户并授权四、连接navicat五、beego连接数据库六、启动beego连接成功...
  • 简介 BeeGo是一个快速开发Go而应用的HTTP框架,他可以用来快速开发API,web以及后端服务等各种应用,是一个restful 的框架,主要涉及灵感来源于tornado,sinatr和flask这三个框架,...beego有八个模块,分别是 ca...
  • 用golang实现注册服务,安装服务,... package main import ( "github.com/astaxie/beego" "github.com/kardianos/service" "os" ) var logger = service.ConsoleLogger type program struct{} fu...
  • Beego初探

    2016-12-06 23:05:19
    使用beego构建一个简单的web项目
  • Beego Config

    2020-12-28 17:58:33
    Beego提供了ini、yaml、xml、json、env等方式的参数配置,并提供不同配置方式的接口。 Beego配置文件解析采用了github.com/beego/beego/v2/core/config包,设计思路来源于database/sql,支持解析的文件格式包括ini、...
  • beego命令

    2019-03-25 20:54:52
    beego 的架构beego 的执行逻辑beego 项目结构M(models 目录)V(views 目录)C(controllers 目录)main.go 是入口文件beego 安装go get github.com/astaxie/beego bee工具 go get github.com/beego/bee new 命令...
  • Beego Main

    2020-12-26 03:10:28
    Beego项目的入口文件为main.go,入口文件内具有个main()主入口函数。 $ vim main.go // 主包 package main // 导入包 import ( _ "gmms/routers" beego "github.com/beego/beego/v2/server/web" ) // 主入口函数 ...
  • Beego Login

    2020-12-31 14:57:42
    使用bee new命令创建新项目,项目名称为gmms。 $ bee new gmms 登录页面 创建登录路由 $ vim gmms/routers/router.go package routers import ( "gmms/controllers" "github.... beego.Router("/...
  • go beego install

    千次阅读 2016-04-21 13:38:06
    首先安装go环境这就不墨迹了。安装博客一找一大堆。 beego官网 beego.me 然后在github 上 go get 获取beego的package  go get github.com/astaxie/beego //框架package  go get github....启动server等
  • Beego Install

    2020-12-26 00:35:48
    beego官网 http://beego.me http://www.topgoer.com go代理地址 https://goproxy.cn/ Begoo是一个使用Go语言开发的应用框架,思路来自于Tornado,路由设计来源于Sinatra。 安装 安装Go Windows安装Go语言环境 ...
  • beego web框架(一)beego介绍与使用

    万次阅读 2017-07-30 12:14:28
    1. beego的使用 1.1. beego的安装 go get github.com/astaxie/beego 1.2. beego的升级 1、直接升级 go get -u github.com/astaxie/beego
  • beego项目运行过程

    千次阅读 2017-03-20 08:34:59
    一:首先man.go,整个程序的入口 func main() { beego.Run() } 然后beego.run()代码 // Run beego application. // beego.Run() default run on HttpPort //
  • Beego之简介

    千次阅读 2020-07-05 09:46:56
    beego 是一个快速开发 Go 应用的 HTTP 框架,他可以用来快速开发 ...beego的执行逻辑 beego 是一个典型的 MVC 架构 Beego的项目结构 从上面的目录结构我们可以看出来 M(models 目录)、V(views 目录)和 C(cont.
  • beego集成swagger

    千次阅读 2018-08-04 22:17:27
    最近在做的一个项目为前端提供rest接口,编程语言为go,框架采用的是beego,在beego框架中集成swagger可以很方便的展示已经实现的后端rest接口。 前提 beego框架的安装和使用可以直接参考beego官网,文档也是...
  • beego 简介

    2019-04-09 12:04:31
    beego 入门 ├── conf │ └── app.conf ├── controllers │ ├── admin │ └── default.go ├── main.go ├── models │ └── models.go ├── static │ ├── css │ ├── ico │ ├── ...
  • beego入门

    2017-09-14 23:38:00
    beego 是一个快速开发 Go 应用的 HTTP 框架,他可以用来快速开发 API、Web 及后端服务等各种应用,是一个 RESTful 的框架,主要设计灵感来源于 tornado、sinatra 和 flask 这三个框架,但是结合了 Go 本身的一些特性...
  • Beego框架学习笔记01--初识Beego

    千次阅读 2018-12-03 20:33:48
    但是偶然听朋友提到了beego,发现beego和前端的Vu e.js,python的dJungle还有flask都好像。这对于有php、python或者web基础的开发者来说是一个很棒的入门优势。所以左右框架什么的都不太了解,所以最终敲定先从相对...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,301
精华内容 520
关键字:

启动beego