Go 闭包实现http全局异常拦截


前言

Golang中,函数是一等公民,使用函数可以实现各种各样的奇淫技巧,比如本文介绍的http全局异常拦截。

在Java中,Spring框架所提供的@ControllerAdvice注解可以实现对服务器全局异常的统一处理。这种方式大大简化了后端程序的异常处理,比如在处理业务逻辑的过程中,可以将不符合要求的操作或数据直接通过throw的方式,提前中止后面的不安全操作;而且通过统一异常拦截处理,可以向用户屏蔽一些敏感的异常描述信息,毕竟往往异常描述只是方便开发人员定位问题,对用户来说往往意义不大。


一、闭包是什么?

闭包就是能够读取其他函数内部变量的函数。 例如在Golang中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。 在本质上,闭包是将函数内部和函数外部连接起来的桥梁。例如下面的代码实现斐波那契数列:

package main

import "fmt"

// 使用闭包实现斐波那契数列
func fib() func() int {
	a, b := 0, 1
	return func() int {
		a, b = b, a+b
		return b
	}
}

func main() {
	f := fib()
	for i := 0; i < 10; i++ {
		fmt.Printf("%d:%d\n", i, f())
	}
	fmt.Println()
}

上面的代码中,fib() 函数返回体是一个匿名函数,该匿名函数引用了 fib() 函数内部的局部变量 ab,从而导致 fib 执行结束后,局部变量 ab 并没有随着 fib() 结束而被销毁,使得外部可以通过匿名函数间接操作了 ab 的值。

二、闭包实现全局拦截器

1.定义http处理器

代码如下(示例):

// 定义处理器函数
type appHandler func(writer http.ResponseWriter, request *http.Request) error

2.定义全局异常接口

代码如下(示例):

// 定义自定义业务异常,内嵌包含了 error 接口
type BusinessErr interface {
	error
	Message() string
	Code() int
}

3.实现全局拦截器

代码如下(示例):

// 使用闭包统一处理异常
func errHander(hadler appHandler) func(http.ResponseWriter, *http.Request) {
	return func(writer http.ResponseWriter, request *http.Request) {
		// 1. 处理全局未捕获异常 panic
		defer func() {
			if r := recover(); r != nil {
				log.Println("Panic: ", r)
				http.Error(writer, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
			}
		}()

		// 2. 处理http请求
		err := hadler(writer, request)

		// 3. 处理http请求明确的异常信息
		if err != nil {
			log.Println("Error occur on handling request: ", err.Error())

			// 自定义业务异常处理
			if userDefineErr, ok := err.(BusinessErr); ok {
				http.Error(writer, userDefineErr.Message(), userDefineErr.Code())
				return
			}

			// 系统明确的异常处理
			var statusCode int
			switch {
			case os.IsNotExist(err):
				statusCode = http.StatusNotFound
			default:
				statusCode = http.StatusInternalServerError
			}
			http.Error(writer, http.StatusText(statusCode), statusCode)
			return
		}
	}
}

4.main

代码如下(示例):

package main

import (
   "net/http"
   "hello/hello"
)

func main() {
	// 定义接口,及其对应的处理器
	http.HandleFunc("/hello", errHander(hello.Handler))

	// 启动服务器,并监听8080端口
	err := http.ListenAndServe(":8080", nil)
	if err != nil {
		panic(err)
	}
}

总结

以上就是今天分享的内容,本文仅仅简单介绍了使用闭包实现http全局异常拦截,而Golang函数还有更多高级玩法,值得我们慢慢探索。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值