Beego 使用教程 7:Web 文件上传下载和错误处理

作者 : admin 本文共22863个字,预计阅读时间需要58分钟 发布时间: 2024-06-16 共1人阅读

beego 是一个用于Go编程语言的开源、高性能的 web 框架

beego 被用于在Go语言中企业应用程序的快速开发,包括RESTful API、web应用程序和后端服务。它的灵感来源于Tornado, Sinatra 和 Flask

beego 官网:http://beego.gocn.vip/

上面的 beego 官网如果访问不到,看这篇文章《beego 官网文档本地环境搭建》

注意:本文的 beego 文档使用的就是本地环境搭建的文档,因为官网文档已经不可用了

beego 官方 github 仓库:https://github.com/beego/beego

上一讲,讲了 web 输入处理,需要的朋友可以查看《Beego 使用教程 6:Web 输入处理》

这一讲,讲解 web 文件上传下载和错误处理,代码使用上一讲的代码

目录

1、文件上传

2、文件下载

3、错误处理

3.1、重定向

3.2、中止此次请求并抛出异常

3.3、自定义 401、403、404、500、503 错误处理

3.4、Controller 定义 Error

3.5、从 panic 中恢复


1、文件上传

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

web.MaxMemory = 1<<22

或者在配置文件中通过如下设置:

maxmemory = 1<<22

与此同时,Beego 提供了另外一个参数,MaxUploadSize来限制最大上传文件大小——如果你一次长传多个文件,那么它限制的就是这些所有文件合并在一起的大小

默认情况下,MaxMemory应该设置得比MaxUploadSize小,这种情况下两个参数合并在一起的效果则是:

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

在 controller 目录下新建 file.go,内容是下面代码

package controller

import (
	"fmt"
	"github.com/beego/beego/v2/server/web"
	"log"
)

type FileController struct {
	web.Controller
}

func (f *FileController) Upload() {
	file, header, er := f.GetFile("file")
	if er != nil {
		log.Fatal("getfile err ", er)
	}
	defer file.Close()
	fmt.Println(header.Filename)
	f.SaveToFile("file", "E:\tmp\file\"+header.Filename)

	f.Ctx.WriteString("上传成功")
}

修改 main.go 为下面代码,添加 Upload 的路由

package main

import (
	"beego-demo/controller"
	"beego-demo/filter"
	"fmt"
	"github.com/beego/beego/v2/core/config"
	"github.com/beego/beego/v2/server/web"
)

func main() {
	//通过config获取自定义配置
	workername, _ := config.String("workername")
	fmt.Println(workername)

	//执行定时任务
	//go job.DemoTask()

	//注册自动路由
	//web.AutoPrefix("api", &controller.UserController{})
	web.CtrlGet("/name", (*controller.UserController).Name)
	web.CtrlGet("/get/:id", (*controller.UserController).GetUserById)
	web.CtrlGet("/get/:id/:num", (*controller.UserController).GetUserByIdAndNum)
	//返回页面
	web.CtrlGet("/page/index", (*controller.PageController).Index)
	web.CtrlGet("/page/f", (*controller.PageController).F)
	web.CtrlGet("/page/main", (*controller.PageController).Main)
	//web输入参数
	web.CtrlGet("/pathparam/:name", (*controller.ParamController).PathParam)
	web.CtrlGet("/getparam", (*controller.ParamController).GetParam)
	web.CtrlPost("/postparam", (*controller.ParamController).PostParam)
	web.CtrlPost("/bindparam", (*controller.ParamController).BindParam)
	//上传文件
	web.CtrlPost("/upload", (*controller.FileController).Upload)

	//注册函数式路由
	controller.RegisterFunctionalRoutes()
	//web命名空间
	controller.RegisterNamespaceRoutes()

	//过滤器
	filter.RegisterFilters()

	//开启 Admin 管理后台
	web.BConfig.Listen.EnableAdmin = true
	web.BConfig.Listen.AdminAddr = "localhost"
	web.BConfig.Listen.AdminPort = 8088

	//web.BConfig.WebConfig.ViewsPath = "pages"

	//开启post 请求 bind绑定请求体
	web.BConfig.CopyRequestBody = true

	//查看已注册路由
	tree := web.PrintTree()
	methods := tree["Data"].(web.M)
	for k, v := range methods {
		fmt.Printf("%s => %v
", k, v)
	}

	//自定义模板函数
	web.AddFuncMap("bookName", bookName)

	web.Run()
}

// 自定义模板函数添加书名号
func bookName(in string) (out string) {
	out = "《" + in + "》"
	return
}

修改 login.html 为下面代码


    

登录

post 请求



运行效果

浏览器访问:http://localhost:9090/page/main

Beego 使用教程 7:Web 文件上传下载和错误处理插图

2、文件下载

Beego 直接提供了一个下载文件的方法Download

func (output *BeegoOutput) Download(file string, filename ...string) {}

修改 controller 目录下 file.go 为下面代码

package controller

import (
	"fmt"
	"github.com/beego/beego/v2/server/web"
	"log"
)

type FileController struct {
	web.Controller
}

func (f *FileController) Upload() {
	file, header, er := f.GetFile("file")
	if er != nil {
		log.Fatal("getfile err ", er)
	}
	defer file.Close()
	fmt.Println(header.Filename)
	f.SaveToFile("file", "E:\tmp\file\"+header.Filename)

	f.Ctx.WriteString("上传成功")
}

func (f *FileController) Download() {
	f.Ctx.Output.Download("E:\tmp\file.png", "1.png")
}

修改 main.go 为下面代码,添加 Download 的路由

package main

import (
	"beego-demo/controller"
	"beego-demo/filter"
	"fmt"
	"github.com/beego/beego/v2/core/config"
	"github.com/beego/beego/v2/server/web"
)

func main() {
	//通过config获取自定义配置
	workername, _ := config.String("workername")
	fmt.Println(workername)

	//执行定时任务
	//go job.DemoTask()

	//注册自动路由
	//web.AutoPrefix("api", &controller.UserController{})
	web.CtrlGet("/name", (*controller.UserController).Name)
	web.CtrlGet("/get/:id", (*controller.UserController).GetUserById)
	web.CtrlGet("/get/:id/:num", (*controller.UserController).GetUserByIdAndNum)
	//返回页面
	web.CtrlGet("/page/index", (*controller.PageController).Index)
	web.CtrlGet("/page/f", (*controller.PageController).F)
	web.CtrlGet("/page/main", (*controller.PageController).Main)
	//web输入参数
	web.CtrlGet("/pathparam/:name", (*controller.ParamController).PathParam)
	web.CtrlGet("/getparam", (*controller.ParamController).GetParam)
	web.CtrlPost("/postparam", (*controller.ParamController).PostParam)
	web.CtrlPost("/bindparam", (*controller.ParamController).BindParam)
	//上传文件
	web.CtrlPost("/upload", (*controller.FileController).Upload)
	//下载文件
	web.CtrlGet("/download", (*controller.FileController).Download)

	//注册函数式路由
	controller.RegisterFunctionalRoutes()
	//web命名空间
	controller.RegisterNamespaceRoutes()

	//过滤器
	filter.RegisterFilters()

	//开启 Admin 管理后台
	web.BConfig.Listen.EnableAdmin = true
	web.BConfig.Listen.AdminAddr = "localhost"
	web.BConfig.Listen.AdminPort = 8088

	//web.BConfig.WebConfig.ViewsPath = "pages"

	//开启post 请求 bind绑定请求体
	web.BConfig.CopyRequestBody = true

	//查看已注册路由
	tree := web.PrintTree()
	methods := tree["Data"].(web.M)
	for k, v := range methods {
		fmt.Printf("%s => %v
", k, v)
	}

	//自定义模板函数
	web.AddFuncMap("bookName", bookName)

	web.Run()
}

// 自定义模板函数添加书名号
func bookName(in string) (out string) {
	out = "《" + in + "》"
	return
}

浏览器请求:http://localhost:9090/download

运行效果

Beego 使用教程 7:Web 文件上传下载和错误处理插图(1)

3、错误处理

3.1、重定向

在 controller 目录下新建 error.go,error.go 内容是下面代码

package controller

import (
	"github.com/beego/beego/v2/server/web"
)

type ErrorHandlerController struct {
	web.Controller
}

func (this *ErrorHandlerController) GetUserName() {
	this.Redirect("/page/main", 302)
}

在 main.go 中添加 GetUserName 路由

package main

import (
	"beego-demo/controller"
	"beego-demo/filter"
	"fmt"
	"github.com/beego/beego/v2/core/config"
	"github.com/beego/beego/v2/server/web"
	"github.com/beego/beego/v2/server/web/context"
)

func main() {
	//通过config获取自定义配置
	workername, _ := config.String("workername")
	fmt.Println(workername)

	//执行定时任务
	//go job.DemoTask()

	//注册自动路由
	//web.AutoPrefix("api", &controller.UserController{})
	web.CtrlGet("/name", (*controller.UserController).Name)
	web.CtrlGet("/get/:id", (*controller.UserController).GetUserById)
	web.CtrlGet("/get/:id/:num", (*controller.UserController).GetUserByIdAndNum)
	//返回页面
	web.CtrlGet("/page/index", (*controller.PageController).Index)
	web.CtrlGet("/page/f", (*controller.PageController).F)
	web.CtrlGet("/page/main", (*controller.PageController).Main)
	//web输入参数
	web.CtrlGet("/pathparam/:name", (*controller.ParamController).PathParam)
	web.CtrlGet("/getparam", (*controller.ParamController).GetParam)
	web.CtrlPost("/postparam", (*controller.ParamController).PostParam)
	web.CtrlPost("/bindparam", (*controller.ParamController).BindParam)
	//上传文件
	web.CtrlPost("/upload", (*controller.FileController).Upload)
	//下载文件
	web.CtrlGet("/download", (*controller.FileController).Download)
	//错误处理
	web.CtrlGet("/getUserName", (*controller.ErrorHandlerController).GetUserName)

	//注册函数式路由
	controller.RegisterFunctionalRoutes()
	//web命名空间
	controller.RegisterNamespaceRoutes()

	//过滤器
	filter.RegisterFilters()

	//开启 Admin 管理后台
	web.BConfig.Listen.EnableAdmin = true
	web.BConfig.Listen.AdminAddr = "localhost"
	web.BConfig.Listen.AdminPort = 8088

	//web.BConfig.WebConfig.ViewsPath = "pages"

	//开启post 请求 bind绑定请求体
	web.BConfig.CopyRequestBody = true

	//查看已注册路由
	tree := web.PrintTree()
	methods := tree["Data"].(web.M)
	for k, v := range methods {
		fmt.Printf("%s => %v
", k, v)
	}

	//自定义模板函数
	web.AddFuncMap("bookName", bookName)

	web.Run()
}

// 自定义模板函数添加书名号
func bookName(in string) (out string) {
	out = "《" + in + "》"
	return
}

运行效果

浏览器访问:http://localhost:9090/getUserName

Beego 使用教程 7:Web 文件上传下载和错误处理插图(2)

3.2、中止此次请求并抛出异常

在 error.go 中修改为下面代码

package controller

import (
	"github.com/beego/beego/v2/server/web"
)

type ErrorHandlerController struct {
	web.Controller
}

func (this *ErrorHandlerController) GetUserName() {
	this.Redirect("/page/main", 302)
}

func (this *ErrorHandlerController) GetUserAge() {
	//this.Abort("404") 之后的代码不会再执行
	this.Abort("404")
	this.Ctx.WriteString("我的年龄是18岁")
}

在 main.go 中添加 GetUserAge 的路由

package main

import (
	"beego-demo/controller"
	"beego-demo/filter"
	"fmt"
	"github.com/beego/beego/v2/core/config"
	"github.com/beego/beego/v2/server/web"
)

func main() {
	//通过config获取自定义配置
	workername, _ := config.String("workername")
	fmt.Println(workername)

	//执行定时任务
	//go job.DemoTask()

	//注册自动路由
	//web.AutoPrefix("api", &controller.UserController{})
	web.CtrlGet("/name", (*controller.UserController).Name)
	web.CtrlGet("/get/:id", (*controller.UserController).GetUserById)
	web.CtrlGet("/get/:id/:num", (*controller.UserController).GetUserByIdAndNum)
	//返回页面
	web.CtrlGet("/page/index", (*controller.PageController).Index)
	web.CtrlGet("/page/f", (*controller.PageController).F)
	web.CtrlGet("/page/main", (*controller.PageController).Main)
	//web输入参数
	web.CtrlGet("/pathparam/:name", (*controller.ParamController).PathParam)
	web.CtrlGet("/getparam", (*controller.ParamController).GetParam)
	web.CtrlPost("/postparam", (*controller.ParamController).PostParam)
	web.CtrlPost("/bindparam", (*controller.ParamController).BindParam)
	//上传文件
	web.CtrlPost("/upload", (*controller.FileController).Upload)
	//下载文件
	web.CtrlGet("/download", (*controller.FileController).Download)
	//错误处理
	web.CtrlGet("/getUserName", (*controller.ErrorHandlerController).GetUserName)
	web.CtrlGet("/getUserAge", (*controller.ErrorHandlerController).GetUserAge)

	//注册函数式路由
	controller.RegisterFunctionalRoutes()
	//web命名空间
	controller.RegisterNamespaceRoutes()

	//过滤器
	filter.RegisterFilters()

	//开启 Admin 管理后台
	web.BConfig.Listen.EnableAdmin = true
	web.BConfig.Listen.AdminAddr = "localhost"
	web.BConfig.Listen.AdminPort = 8088

	//web.BConfig.WebConfig.ViewsPath = "pages"

	//开启post 请求 bind绑定请求体
	web.BConfig.CopyRequestBody = true

	//查看已注册路由
	tree := web.PrintTree()
	methods := tree["Data"].(web.M)
	for k, v := range methods {
		fmt.Printf("%s => %v
", k, v)
	}

	//自定义模板函数
	web.AddFuncMap("bookName", bookName)

	web.Run()
}

// 自定义模板函数添加书名号
func bookName(in string) (out string) {
	out = "《" + in + "》"
	return
}

运行效果

浏览器访问:http://localhost:9090/getUserAge

Beego 使用教程 7:Web 文件上传下载和错误处理插图(3)

3.3、自定义 401、403、404、500、503 错误处理

web 框架默认支持 401、403、404、500、503 这几种错误的处理。用户可以自定义相应的错误处理

在 error.go 中修改为下面代码

package main

import (
	"beego-demo/controller"
	"beego-demo/filter"
	"fmt"
	"github.com/beego/beego/v2/core/config"
	"github.com/beego/beego/v2/server/web"
	"html/template"
	"net/http"
)

func main() {
	//通过config获取自定义配置
	workername, _ := config.String("workername")
	fmt.Println(workername)

	//执行定时任务
	//go job.DemoTask()

	//注册自动路由
	//web.AutoPrefix("api", &controller.UserController{})
	web.CtrlGet("/name", (*controller.UserController).Name)
	web.CtrlGet("/get/:id", (*controller.UserController).GetUserById)
	web.CtrlGet("/get/:id/:num", (*controller.UserController).GetUserByIdAndNum)
	//返回页面
	web.CtrlGet("/page/index", (*controller.PageController).Index)
	web.CtrlGet("/page/f", (*controller.PageController).F)
	web.CtrlGet("/page/main", (*controller.PageController).Main)
	//web输入参数
	web.CtrlGet("/pathparam/:name", (*controller.ParamController).PathParam)
	web.CtrlGet("/getparam", (*controller.ParamController).GetParam)
	web.CtrlPost("/postparam", (*controller.ParamController).PostParam)
	web.CtrlPost("/bindparam", (*controller.ParamController).BindParam)
	//上传文件
	web.CtrlPost("/upload", (*controller.FileController).Upload)
	//下载文件
	web.CtrlGet("/download", (*controller.FileController).Download)
	//错误处理
	web.CtrlGet("/getUserName", (*controller.ErrorHandlerController).GetUserName)
	web.CtrlGet("/getUserAge", (*controller.ErrorHandlerController).GetUserAge)

	//注册函数式路由
	controller.RegisterFunctionalRoutes()
	//web命名空间
	controller.RegisterNamespaceRoutes()

	//过滤器
	filter.RegisterFilters()

	//开启 Admin 管理后台
	web.BConfig.Listen.EnableAdmin = true
	web.BConfig.Listen.AdminAddr = "localhost"
	web.BConfig.Listen.AdminPort = 8088

	//web.BConfig.WebConfig.ViewsPath = "pages"

	//开启post 请求 bind绑定请求体
	web.BConfig.CopyRequestBody = true

	//查看已注册路由
	tree := web.PrintTree()
	methods := tree["Data"].(web.M)
	for k, v := range methods {
		fmt.Printf("%s => %v
", k, v)
	}

	//自定义模板函数
	web.AddFuncMap("bookName", bookName)

	//自定义401返回
	web.ErrorHandler("401", page401)
	//自定义404返回
	web.ErrorHandler("404", page404)

	web.Run()
}

// 自定义模板函数添加书名号
func bookName(in string) (out string) {
	out = "《" + in + "》"
	return
}

func page401(rw http.ResponseWriter, r *http.Request) {
	t, _ := template.New("401.html").ParseFiles(web.BConfig.WebConfig.ViewsPath + "/401.html")
	data := make(map[string]interface{})
	data["content"] = "没有访问权限"
	t.Execute(rw, data)
}

func page404(rw http.ResponseWriter, r *http.Request) {
	t, _ := template.New("404.html").ParseFiles(web.BConfig.WebConfig.ViewsPath + "/404.html")
	data := make(map[string]interface{})
	data["content"] = "页面没找到"
	t.Execute(rw, data)
}

自定义401 和 404 返回,笔者返回自己定义的页面

下面是 401 和 404 页面,在 views 目录下新建 401.html 和 404.html

401.html 代码




    
    Title


我是401
{{.content}}

404.html 代码




    
    Title


我是404
{{.content}}

运行测试

浏览器访问:http://localhost:9090/getUserAge

Beego 使用教程 7:Web 文件上传下载和错误处理插图(4)

3.4、自定义字符串错误类型处理函数

除了上面的 401、403、404、500、503 这几种错误的处理之外,Beego 更加人性化的还有一个设计就是支持用户自定义字符串错误类型处理函数

修改 main.go 为下面代码

package main

import (
	"beego-demo/controller"
	"beego-demo/filter"
	"fmt"
	"github.com/beego/beego/v2/core/config"
	"github.com/beego/beego/v2/server/web"
	"html/template"
	"net/http"
)

func main() {
	//通过config获取自定义配置
	workername, _ := config.String("workername")
	fmt.Println(workername)

	//执行定时任务
	//go job.DemoTask()

	//注册自动路由
	//web.AutoPrefix("api", &controller.UserController{})
	web.CtrlGet("/name", (*controller.UserController).Name)
	web.CtrlGet("/get/:id", (*controller.UserController).GetUserById)
	web.CtrlGet("/get/:id/:num", (*controller.UserController).GetUserByIdAndNum)
	//返回页面
	web.CtrlGet("/page/index", (*controller.PageController).Index)
	web.CtrlGet("/page/f", (*controller.PageController).F)
	web.CtrlGet("/page/main", (*controller.PageController).Main)
	//web输入参数
	web.CtrlGet("/pathparam/:name", (*controller.ParamController).PathParam)
	web.CtrlGet("/getparam", (*controller.ParamController).GetParam)
	web.CtrlPost("/postparam", (*controller.ParamController).PostParam)
	web.CtrlPost("/bindparam", (*controller.ParamController).BindParam)
	//上传文件
	web.CtrlPost("/upload", (*controller.FileController).Upload)
	//下载文件
	web.CtrlGet("/download", (*controller.FileController).Download)
	//错误处理
	web.CtrlGet("/getUserName", (*controller.ErrorHandlerController).GetUserName)
	web.CtrlGet("/getUserAge", (*controller.ErrorHandlerController).GetUserAge)
	web.CtrlGet("/getUserAddr", (*controller.ErrorHandlerController).GetUserAddr)

	//注册函数式路由
	controller.RegisterFunctionalRoutes()
	//web命名空间
	controller.RegisterNamespaceRoutes()

	//过滤器
	filter.RegisterFilters()

	//开启 Admin 管理后台
	web.BConfig.Listen.EnableAdmin = true
	web.BConfig.Listen.AdminAddr = "localhost"
	web.BConfig.Listen.AdminPort = 8088

	//web.BConfig.WebConfig.ViewsPath = "pages"

	//开启post 请求 bind绑定请求体
	web.BConfig.CopyRequestBody = true

	//查看已注册路由
	tree := web.PrintTree()
	methods := tree["Data"].(web.M)
	for k, v := range methods {
		fmt.Printf("%s => %v
", k, v)
	}

	//自定义模板函数
	web.AddFuncMap("bookName", bookName)

	//自定义401返回
	web.ErrorHandler("401", page401)
	//自定义404返回
	web.ErrorHandler("404", page404)

	web.ErrorHandler("dbError", dbError)

	web.Run()
}

// 自定义模板函数添加书名号
func bookName(in string) (out string) {
	out = "《" + in + "》"
	return
}

func page401(rw http.ResponseWriter, r *http.Request) {
	t, _ := template.New("401.html").ParseFiles(web.BConfig.WebConfig.ViewsPath + "/401.html")
	data := make(map[string]interface{})
	data["content"] = "没有访问权限"
	t.Execute(rw, data)
}

func page404(rw http.ResponseWriter, r *http.Request) {
	t, _ := template.New("404.html").ParseFiles(web.BConfig.WebConfig.ViewsPath + "/404.html")
	data := make(map[string]interface{})
	data["content"] = "页面没找到"
	t.Execute(rw, data)
}

func dbError(rw http.ResponseWriter, r *http.Request) {
	t, _ := template.New("dberror.html").ParseFiles(web.BConfig.WebConfig.ViewsPath + "/dberror.html")
	data := make(map[string]interface{})
	data["content"] = "我是自定义字符串错误类型处理函数"
	t.Execute(rw, data)
}

在 views 目录下新建 dberror.html ,dberror.html 内容是下面代码




    
    Title


dberror
{{.content}}

修改 error.go 为下面代码

package controller

import (
	"github.com/beego/beego/v2/server/web"
)

type ErrorHandlerController struct {
	web.Controller
}

func (this *ErrorHandlerController) GetUserName() {
	this.Redirect("/page/main", 302)
}

func (this *ErrorHandlerController) GetUserAge() {
	//this.Abort("404") 之后的代码不会再执行
	this.Abort("404")
	this.Ctx.WriteString("我的年龄是18岁")
}

func (this *ErrorHandlerController) GetUserAddr() {
	this.Abort("dbError")
}

运行效果

浏览器访问:http://localhost:9090/getUserAddr

Beego 使用教程 7:Web 文件上传下载和错误处理插图(5)

3.4、Controller 定义 Error

从 1.4.3 版本开始,支持 Controller 方式定义 Error 错误处理函数,这样就可以充分利用系统自带的模板处理,以及 context 等方法

在 controller 目录下新建 er.go ,内容是下面代码

package controller

import (
	"fmt"
	"github.com/beego/beego/v2/server/web"
)

type ErrorController struct {
	web.Controller
}

func (c *ErrorController) Error501() {
	fmt.Println("501.html")
	c.Data["content"] = "server error"
	c.TplName = "501.html"
}

通过上面的代码我们可以看到,函数都是有一定规律的,都是 Error 开头,后面的名字就是我们调用 Abort 的名字,例如 Error501 函数其实调用对应的就是 Abort(“501”)
只要在 web.Run 之前采用 controller.ErrorController 注册这个错误处理函数就可以了

下面是 main.go 的代码

package main

import (
	"beego-demo/controller"
	"beego-demo/filter"
	"fmt"
	"github.com/beego/beego/v2/core/config"
	"github.com/beego/beego/v2/server/web"
	"html/template"
	"net/http"
)

func main() {
	//通过config获取自定义配置
	workername, _ := config.String("workername")
	fmt.Println(workername)

	//执行定时任务
	//go job.DemoTask()

	//注册自动路由
	//web.AutoPrefix("api", &controller.UserController{})
	web.CtrlGet("/name", (*controller.UserController).Name)
	web.CtrlGet("/get/:id", (*controller.UserController).GetUserById)
	web.CtrlGet("/get/:id/:num", (*controller.UserController).GetUserByIdAndNum)
	//返回页面
	web.CtrlGet("/page/index", (*controller.PageController).Index)
	web.CtrlGet("/page/f", (*controller.PageController).F)
	web.CtrlGet("/page/main", (*controller.PageController).Main)
	//web输入参数
	web.CtrlGet("/pathparam/:name", (*controller.ParamController).PathParam)
	web.CtrlGet("/getparam", (*controller.ParamController).GetParam)
	web.CtrlPost("/postparam", (*controller.ParamController).PostParam)
	web.CtrlPost("/bindparam", (*controller.ParamController).BindParam)
	//上传文件
	web.CtrlPost("/upload", (*controller.FileController).Upload)
	//下载文件
	web.CtrlGet("/download", (*controller.FileController).Download)
	//错误处理
	web.CtrlGet("/getUserName", (*controller.ErrorHandlerController).GetUserName)
	web.CtrlGet("/getUserAge", (*controller.ErrorHandlerController).GetUserAge)
	web.CtrlGet("/getUserAddr", (*controller.ErrorHandlerController).GetUserAddr)
	web.CtrlGet("/getUserGender", (*controller.ErrorHandlerController).GetUserGender)
	//注册错误处理函数
	web.ErrorController(&controller.ErrorController{})

	//注册函数式路由
	controller.RegisterFunctionalRoutes()
	//web命名空间
	controller.RegisterNamespaceRoutes()

	//过滤器
	filter.RegisterFilters()

	//开启 Admin 管理后台
	web.BConfig.Listen.EnableAdmin = true
	web.BConfig.Listen.AdminAddr = "localhost"
	web.BConfig.Listen.AdminPort = 8088

	//web.BConfig.WebConfig.ViewsPath = "pages"

	//开启post 请求 bind绑定请求体
	web.BConfig.CopyRequestBody = true

	//查看已注册路由
	tree := web.PrintTree()
	methods := tree["Data"].(web.M)
	for k, v := range methods {
		fmt.Printf("%s => %v
", k, v)
	}

	//自定义模板函数
	web.AddFuncMap("bookName", bookName)

	//自定义401返回
	web.ErrorHandler("401", page401)
	//自定义404返回
	web.ErrorHandler("404", page404)

	web.ErrorHandler("dbError", dbError)

	web.Run()
}

// 自定义模板函数添加书名号
func bookName(in string) (out string) {
	out = "《" + in + "》"
	return
}

func page401(rw http.ResponseWriter, r *http.Request) {
	t, _ := template.New("401.html").ParseFiles(web.BConfig.WebConfig.ViewsPath + "/401.html")
	data := make(map[string]interface{})
	data["content"] = "没有访问权限"
	t.Execute(rw, data)
}

func page404(rw http.ResponseWriter, r *http.Request) {
	t, _ := template.New("404.html").ParseFiles(web.BConfig.WebConfig.ViewsPath + "/404.html")
	data := make(map[string]interface{})
	data["content"] = "页面没找到"
	t.Execute(rw, data)
}

func dbError(rw http.ResponseWriter, r *http.Request) {
	t, _ := template.New("dberror.html").ParseFiles(web.BConfig.WebConfig.ViewsPath + "/dberror.html")
	data := make(map[string]interface{})
	data["content"] = "我是自定义字符串错误类型处理函数"
	t.Execute(rw, data)
}

修改 error.go 为下面代码

package controller

import (
	"github.com/beego/beego/v2/server/web"
)

type ErrorHandlerController struct {
	web.Controller
}

func (this *ErrorHandlerController) GetUserName() {
	this.Redirect("/page/main", 302)
}

func (this *ErrorHandlerController) GetUserAge() {
	//this.Abort("404") 之后的代码不会再执行
	this.Abort("404")
	this.Ctx.WriteString("我的年龄是18岁")
}

func (this *ErrorHandlerController) GetUserAddr() {
	this.Abort("dbError")
}

func (this *ErrorHandlerController) GetUserGender() {
	this.Abort("501")
}

在 views 目录下新建 501.html,代码是下面内容




    
    Title


我是501

运行测试

浏览器请求:http://localhost:9090/getUserGender

Beego 使用教程 7:Web 文件上传下载和错误处理插图(6)

3.5、从 panic 中恢复

如果你希望用户在服务器处理请求过程中,即便发生了 panic 依旧能够返回响应,那么可以使用 Beego 的恢复机制。该机制是默认开启的。依赖于配置项

web.BConfig.RecoverPanic = true

如果你需要关闭,那么将这个配置项设置为 false 就可以

如果你想自定义panic之后的处理行为,那么可以重新设置 web.BConfig.RecoverFunc

web.BConfig.RecoverFunc = func(context *context.Context, config *web.Config) {
	if err := recover(); err != nil {
		context.WriteString(fmt.Sprintf("you panic, err: %v", err))
	}
}

千万要注意:你永远需要检测 recover的结果,并且将从 panic中恢复过来的逻辑放在检测到recover返回不为 nil的代码里面

注意:自定义panic之后的处理行为会覆盖前面的自定义错误处理

修改 main.go 为下面代码

package main

import (
	"beego-demo/controller"
	"beego-demo/filter"
	"fmt"
	"github.com/beego/beego/v2/core/config"
	"github.com/beego/beego/v2/server/web"
	"github.com/beego/beego/v2/server/web/context"
	"html/template"
	"net/http"
)

func main() {
	//通过config获取自定义配置
	workername, _ := config.String("workername")
	fmt.Println(workername)

	//执行定时任务
	//go job.DemoTask()

	//注册自动路由
	//web.AutoPrefix("api", &controller.UserController{})
	web.CtrlGet("/name", (*controller.UserController).Name)
	web.CtrlGet("/get/:id", (*controller.UserController).GetUserById)
	web.CtrlGet("/get/:id/:num", (*controller.UserController).GetUserByIdAndNum)
	//返回页面
	web.CtrlGet("/page/index", (*controller.PageController).Index)
	web.CtrlGet("/page/f", (*controller.PageController).F)
	web.CtrlGet("/page/main", (*controller.PageController).Main)
	//web输入参数
	web.CtrlGet("/pathparam/:name", (*controller.ParamController).PathParam)
	web.CtrlGet("/getparam", (*controller.ParamController).GetParam)
	web.CtrlPost("/postparam", (*controller.ParamController).PostParam)
	web.CtrlPost("/bindparam", (*controller.ParamController).BindParam)
	//上传文件
	web.CtrlPost("/upload", (*controller.FileController).Upload)
	//下载文件
	web.CtrlGet("/download", (*controller.FileController).Download)
	//错误处理
	web.CtrlGet("/getUserName", (*controller.ErrorHandlerController).GetUserName)
	web.CtrlGet("/getUserAge", (*controller.ErrorHandlerController).GetUserAge)
	web.CtrlGet("/getUserAddr", (*controller.ErrorHandlerController).GetUserAddr)
	web.CtrlGet("/getUserGender", (*controller.ErrorHandlerController).GetUserGender)
	//注册错误处理函数
	web.ErrorController(&controller.ErrorController{})

	//注册函数式路由
	controller.RegisterFunctionalRoutes()
	//web命名空间
	controller.RegisterNamespaceRoutes()

	//过滤器
	filter.RegisterFilters()

	//开启 Admin 管理后台
	web.BConfig.Listen.EnableAdmin = true
	web.BConfig.Listen.AdminAddr = "localhost"
	web.BConfig.Listen.AdminPort = 8088

	//web.BConfig.WebConfig.ViewsPath = "pages"

	//开启post 请求 bind绑定请求体
	web.BConfig.CopyRequestBody = true

	//查看已注册路由
	tree := web.PrintTree()
	methods := tree["Data"].(web.M)
	for k, v := range methods {
		fmt.Printf("%s => %v
", k, v)
	}

	//自定义模板函数
	web.AddFuncMap("bookName", bookName)

	//自定义401返回
	web.ErrorHandler("401", page401)
	//自定义404返回
	web.ErrorHandler("404", page404)

	web.ErrorHandler("dbError", dbError)

	web.BConfig.RecoverFunc = func(context *context.Context, config *web.Config) {
		if err := recover(); err != nil {
			context.WriteString(fmt.Sprintf("you panic, err: %v", err))
		}
	}

	web.Run()
}

// 自定义模板函数添加书名号
func bookName(in string) (out string) {
	out = "《" + in + "》"
	return
}

func page401(rw http.ResponseWriter, r *http.Request) {
	t, _ := template.New("401.html").ParseFiles(web.BConfig.WebConfig.ViewsPath + "/401.html")
	data := make(map[string]interface{})
	data["content"] = "没有访问权限"
	t.Execute(rw, data)
}

func page404(rw http.ResponseWriter, r *http.Request) {
	t, _ := template.New("404.html").ParseFiles(web.BConfig.WebConfig.ViewsPath + "/404.html")
	data := make(map[string]interface{})
	data["content"] = "页面没找到"
	t.Execute(rw, data)
}

func dbError(rw http.ResponseWriter, r *http.Request) {
	t, _ := template.New("dberror.html").ParseFiles(web.BConfig.WebConfig.ViewsPath + "/dberror.html")
	data := make(map[string]interface{})
	data["content"] = "我是自定义字符串错误类型处理函数"
	t.Execute(rw, data)
}

运行效果

请求之前的错误页面

Beego 使用教程 7:Web 文件上传下载和错误处理插图(7)

从 panic 中恢复更像是统一的错误处理

下一讲:《Beego 使用教程 8:Session 和 Cookie》​​​​​​​

至此完 

本站无任何商业行为
个人在线分享 » Beego 使用教程 7:Web 文件上传下载和错误处理
E-->