标签:comm new log bsp use lse hub 位置 好处
确保调用在函数结束时发生
参数在defer语句时计算
defer列表为先进后出
error vs panic : 意料之中用error比如文件打不开,意料之外用panic比如数组越界
创建目录:errorhandling下面再创建目录defer
//defer里面是相当于有一个栈 先进后出 defer好处:不怕中间有return
func tryDefer() {
defer fmt.Println(1)
defer fmt.Println(2)
fmt.Println(3)
//第一种:return
panic("eror occurred") //第二种
fmt.Println(4)
}//输出是3 2 1
详情参加functional https://www.cnblogs.com/ycx95/p/9362175.html
package main
import (
"fmt"
"os"
"bufio"
"imooc.com/ccmouse/learngo/functional/fib"
)
func tryDefer() {
for i := 0; i < 100; i++ {
defer fmt.Println(i)
if i == 30 { //由于现进后出 输出就是:30 29 ... 1
// Uncomment panic to see
// how it works with defer
// panic("printed too many")
}
}
}
func writeFile(filename string) {
file, err := os.OpenFile(filename,
os.O_EXCL|os.O_CREATE|os.O_WRONLY, 0666) //err只是一个值 可以针对值进行处理
if err != nil { //错误处理 细致的错误处理 如果文件存在:输出会提示文件存在
if pathError, ok := err.(*os.PathError); !ok {
panic(err)
} else {
fmt.Printf("%s, %s, %s\n",
pathError.Op,
pathError.Path,
pathError.Err)
}
return
}
defer file.Close() //file写完了要关闭
writer := bufio.NewWriter(file) // 直接file写文件很慢,因此用bufio包装一下
defer writer.Flush() //导进新创建的fib.txt文件里面
f := fib.Fibonacci()
for i := 0; i < 20; i++ { //写前20个fib数列
fmt.Fprintln(writer, f())
}
}
func main() {
tryDefer()
writeFile("fib.txt") //运行程序这里会创建一个fib.txt文件
}
制造一个错误(程序会挂掉)
将原来的: file,err := os.Create(filename) //Create是openfile加了一些状态 直接修改为: file, err := os.OpenFile(filename, os.O_EXCL|os.O_CREATE|os.O_WRONLY, 0666) //0666是一个权限
处理挂掉的错误:如何对err进行细化处理(详见上面代码writefile的error处理部分
自己写error:err = errors.New("this is a custom error“) 其实error就是一个interface
错误处理:
file,err := os.Open("abc.txt")
if err!= nil {
if pathError,ok := err.(*os.PathError);ok {
fmt.Println(pathError.Err)
}else{
fmt.Println("unknown error",err)
}
新建目录:errorhanding目录下创建 filelistingserver 目录
handler.go ( 位置 errorhandling/filelistingserver/filelisting)
package filelisting
import (
"fmt"
"io/ioutil"
"net/http"
"os"
"strings"
)
const prefix = "/list/"
type userError string
func (e userError) Error() string {
return e.Message()
}
func (e userError) Message() string {
return string(e)
}
func HandleFileList(writer http.ResponseWriter,
request *http.Request) error {
fmt.Println()
if strings.Index(
request.URL.Path, prefix) != 0 {
return userError(
fmt.Sprintf("path %s must start "+
"with %s",
request.URL.Path, prefix))
}
path := request.URL.Path[len(prefix):]
file, err := os.Open(path)
if err != nil {
return err //有错就return出去外面有处理
}
defer file.Close()
all, err := ioutil.ReadAll(file)
if err != nil {
return err
}
writer.Write(all)
return nil
}
web.go(位置 errorhandling/filelistingserver)
package main
import (
"log" //这里视频中所写是 github.com/gpmgo/gopm/modules/log
"net/http"
_ "net/http/pprof"
"os"
"imooc.com/ccmouse/learngo/errhandling/filelistingserver/filelisting"
)
//返回一个err
type appHandler func(writer http.ResponseWriter,
request *http.Request) error
//包装errHandler返回的err,然后返回一个函数 特点:输入是一个函数 输出也是一个函数
func errWrapper(
handler appHandler) func(
http.ResponseWriter, *http.Request) {
return func(writer http.ResponseWriter,
request *http.Request) {
// panic
defer func() {
if r := recover(); r != nil {
log.Printf("Panic: %v", r)
http.Error(writer,
http.StatusText(http.StatusInternalServerError),
http.StatusInternalServerError)
}
}()
err := handler(writer, request)
//处理err进行处理
if err != nil {
log.Printf("Error occurred "+
"handling request: %s",
err.Error())
// user error
if userErr, ok := err.(userError); ok {
http.Error(writer,
userErr.Message(),
http.StatusBadRequest)
return
}
// system error
code := http.StatusOK
switch {
case os.IsNotExist(err):
code = http.StatusNotFound
case os.IsPermission(err):
code = http.StatusForbidden
default:
code = http.StatusInternalServerError
}
http.Error(writer,
http.StatusText(code), code)
}
}
}
type userError interface {
error
Message() string
}
func main() {
http.HandleFunc("/",
errWrapper(filelisting.HandleFileList))
err := http.ListenAndServe(":8888", nil) //开服务器 打开服务器输入:localhost:8888/list/fib.txt
if err != nil {
panic(err)
}
}
//测试时候:管理员目录时候cp fib.txt fib2.txt 浏览器可以访问 让别人没有权限:chmod 500 fib2.txt 浏览器输出:Forbidden
errwrapper_test.go(位置 errorhandling/filelistingserver)
package main
import (
"errors"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
)
func errPanic(_ http.ResponseWriter,
_ *http.Request) error {
panic(123)
}
type testingUserError string
func (e testingUserError) Error() string {
return e.Message()
}
func (e testingUserError) Message() string {
return string(e)
}
func errUserError(_ http.ResponseWriter,
_ *http.Request) error {
return testingUserError("user error")
}
func errNotFound(_ http.ResponseWriter,
_ *http.Request) error {
return os.ErrNotExist
}
func errNoPermission(_ http.ResponseWriter,
_ *http.Request) error {
return os.ErrPermission
}
func errUnknown(_ http.ResponseWriter,
_ *http.Request) error {
return errors.New("unknown error")
}
func noError(writer http.ResponseWriter,
_ *http.Request) error {
fmt.Fprintln(writer, "no error")
return nil
}
var tests = []struct {
h appHandler
code int
message string
}{
{errPanic, 500, "Internal Server Error"},
{errUserError, 400, "user error"},
{errNotFound, 404, "Not Found"},
{errNoPermission, 403, "Forbidden"},
{errUnknown, 500, "Internal Server Error"},
{noError, 200, "no error"},
}
func TestErrWrapper(t *testing.T) {
for _, tt := range tests {
f := errWrapper(tt.h)
response := httptest.NewRecorder()
request := httptest.NewRequest(
http.MethodGet,
"http://www.imooc.com", nil)
f(response, request)
verifyResponse(response.Result(),
tt.code, tt.message, t)
}
}
func TestErrWrapperInServer(t *testing.T) {
for _, tt := range tests {
f := errWrapper(tt.h)
server := httptest.NewServer(
http.HandlerFunc(f))
resp, _ := http.Get(server.URL)
verifyResponse(
resp, tt.code, tt.message, t)
}
}
func verifyResponse(resp *http.Response,
expectedCode int, expectedMsg string,
t *testing.T) {
b, _ := ioutil.ReadAll(resp.Body)
body := strings.Trim(string(b), "\n")
if resp.StatusCode != expectedCode ||
body != expectedMsg {
t.Errorf("expect (%d, %s); "+
"got (%d, %s)",
expectedCode, expectedMsg,
resp.StatusCode, body)
}
}
注意:不能经常用
停止当前函数执行,一直向上返回,执行每一层的defer,如果没有遇见recover则程序退出
与panic对应
仅在defer调用中使用,获取panic的值,如果无法处理可重新panic
例子:
package main
import (
"fmt"
)
func tryRecover() {
defer func() { //这里写一个匿名函数 注意最后加的()
r := recover() //哈哈,这里是recover
if r == nil {
fmt.Println("Nothing to recover. " +
"Please try uncomment errors " +
"below.")
return
}
if err, ok := r.(error); ok {
fmt.Println("Error occurred:", err) //的确是err
} else {
panic(fmt.Sprintf(
"I don‘t know what to do: %v", r))
}
}()
// Uncomment each block to see different panic
// scenarios.
// Normal error
//panic(errors.New("this is an error"))
// Division by zero
//b := 0
//a := 5 / b
//fmt.Println(a)
// Causes re-panic
//panic(123)
}
func main() {
tryRecover()
}
标签:comm new log bsp use lse hub 位置 好处
原文地址:https://www.cnblogs.com/ycx95/p/9366750.html