我们的Web应用一旦上线之后,那么各种错误出现的概率都有,Web应用日常运行中可能出现多种错误,具体如下所示:

  • 数据库错误:指与访问数据库服务器或数据相关的错误。例如,以下可能出现的一些数据库错误。

    • 连接错误:这一类错误可能是数据库服务器网络断开、用户名密码不正确、或者数据库不存在。
    • 查询错误:使用的SQL非法导致错误,这样子SQL错误如果程序经过严格的测试应该可以避免。
    • 数据错误:数据库中的约束冲突,例如一个唯一字段中插入一条重复主键的值就会报错,但是如果你的应用程序在上线之前经过了严格的测试也是可以避免这类问题。
  • 应用运行时错误:这类错误范围很广,涵盖了代码中出现的几乎所有错误。可能的应用错误的情况如下:

    • 文件系统和权限:应用读取不存在的文件,或者读取没有权限的文件、或者写入一个不允许写入的文件,这些都会导致一个错误。应用读取的文件如果格式不正确也会报错,例如配置文件应该是ini的配置格式,而设置成了json格式就会报错。
    • 第三方应用:如果我们的应用程序耦合了其他第三方接口程序,例如应用程序发表文章之后自动调用接发微博的接口,所以这个接口必须正常运行才能完成我们发表一篇文章的功能。
  • HTTP错误:这些错误是根据用户的请求出现的错误,最常见的就是404错误。虽然可能会出现很多不同的错误,但其中比较常见的错误还有401未授权错误(需要认证才能访问的资源)、403禁止错误(不允许用户访问的资源)和503错误(程序内部出错)。

  • 操作系统出错:这类错误都是由于应用程序上的操作系统出现错误引起的,主要有操作系统的资源被分配完了,导致死机,还有操作系统的磁盘满了,导致无法写入,这样就会引起很多错误。

  • 网络出错:指两方面的错误,一方面是用户请求应用程序的时候出现网络断开,这样就导致连接中断,这种错误不会造成应用程序的崩溃,但是会影响用户访问的效果;另一方面是应用程序读取其他网络上的数据,其他网络断开会导致读取失败,这种需要对应用程序做有效的测试,能够避免这类问题出现的情况下程序崩溃。

错误处理的目标

在实现错误处理之前,我们必须明确错误处理想要达到的目标是什么,错误处理系统应该完成以下工作:

  • 通知访问用户出现错误了:不论出现的是一个系统错误还是用户错误,用户都应当知道Web应用出了问题,用户的这次请求无法正确的完成了。例如,对于用户的错误请求,我们显示一个统一的错误页面(404.html)。出现系统错误时,我们通过自定义的错误页面显示系统暂时不可用之类的错误页面(error.html)。
  • 记录错误:系统出现错误,一般就是我们调用函数的时候返回err不为nil的情况,可以使用前面小节介绍的日志系统记录到日志文件。如果是一些致命错误,则通过邮件通知系统管理员。一般404之类的错误不需要发送邮件,只需要记录到日志系统。
  • 回滚当前的请求操作:如果一个用户请求过程中出现了一个服务器错误,那么已完成的操作需要回滚。下面来看一个例子:一个系统将用户递交的表单保存到数据库,并将这个数据递交到一个第三方服务器,但是第三方服务器挂了,这就导致一个错误,那么先前存储到数据库的表单数据应该删除(应告知无效),而且应该通知用户系统出现错误了。
  • 保证现有程序可运行可服务:我们知道没有人能保证程序一定能够一直正常的运行着,万一哪一天程序崩溃了,那么我们就需要记录错误,然后立刻让程序重新运行起来,让程序继续提供服务,然后再通知系统管理员,通过日志等找出问题。

如何处理错误

错误处理其实我们已经在十一章第一小节里面有过介绍如何设计错误处理,这里我们再从一个例子详细的讲解一下,如何来处理不同的错误:

  • 通知用户出现错误:

    通知用户在访问页面的时候我们可以有两种错误:404.html和error.html,下面分别显示了错误页面的源码:

    <html lang="en">
    <head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>找不到页面</title><meta name="viewport" content="width=device-width, initial-scale=1.0"></head>
    <body>
    <div class="container"><div class="row"><div class="span10"><div class="hero-unit"><h1>404!</h1><p>{{.ErrorInfo}}</p></div></div><!--/span--></div>
    </div>
    </body>
    </html>
    

    另一个源码:

    <html lang="en">
    <head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>系统错误页面</title><meta name="viewport" content="width=device-width, initial-scale=1.0"></head>
    <body>
    <div class="container"><div class="row"><div class="span10"><div class="hero-unit"><h1>系统暂时不可用!</h1><p>{{.ErrorInfo}}</p></div></div><!--/span--></div>
    </div>
    </body>
    </html>
    

    404的错误处理逻辑,如果是系统的错误也是类似的操作,同时我们看到在:

    func (p *MyMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {if r.URL.Path == "/" {sayhelloName(w, r)return}NotFound404(w, r)return
    }func NotFound404(w http.ResponseWriter, r *http.Request) {log.Error("页面找不到")   //记录错误日志t, _ = t.ParseFiles("tmpl/404.html", nil)  //解析模板文件ErrorInfo := "文件找不到" //获取当前用户信息t.Execute(w, ErrorInfo)  //执行模板的merger操作
    }func SystemError(w http.ResponseWriter, r *http.Request) {log.Critical("系统错误")   //系统错误触发了Critical,那么不仅会记录日志还会发送邮件t, _ = t.ParseFiles("tmpl/error.html", nil)  //解析模板文件ErrorInfo := "系统暂时不可用" //获取当前用户信息t.Execute(w, ErrorInfo)  //执行模板的merger操作
    }
    

如何处理异常

我们知道在很多其他语言中有try...catch关键词,用来捕获异常情况,但是其实很多错误都是可以预期发生的,而不需要异常处理,应该当做错误来处理,这也是为什么Go语言采用了函数返回错误的设计,这些函数不会panic,例如如果一个文件找不到,os.Open返回一个错误,它不会panic;如果你向一个中断的网络连接写数据,net.Conn系列类型的Write函数返回一个错误,它们不会panic。这些状态在这样的程序里都是可以预期的。你知道这些操作可能会失败,因为设计者已经用返回错误清楚地表明了这一点。这就是上面所讲的可以预期发生的错误。

但是还有一种情况,有一些操作几乎不可能失败,而且在一些特定的情况下也没有办法返回错误,也无法继续执行,这样情况就应该panic。举个例子:如果一个程序计算x[j],但是j越界了,这部分代码就会导致panic,像这样的一个不可预期严重错误就会引起panic,在默认情况下它会杀掉进程,它允许一个正在运行这部分代码的goroutine从发生错误的panic中恢复运行,发生panic之后,这部分代码后面的函数和代码都不会继续执行,这是Go特意这样设计的,因为要区别于错误和异常,panic其实就是异常处理。如下代码,我们期望通过uid来获取User中的username信息,但是如果uid越界了就会抛出异常,这个时候如果我们没有recover机制,进程就会被杀死,从而导致程序不可服务。因此为了程序的健壮性,在一些地方需要建立recover机制。

func GetUser(uid int) (username string) {defer func() {if x := recover(); x != nil {username = ""}}()username = User[uid]return
}

上面介绍了错误和异常的区别,那么我们在开发程序的时候如何来设计呢?规则很简单:如果你定义的函数有可能失败,它就应该返回一个错误。当我调用其他package的函数时,如果这个函数实现的很好,我不需要担心它会panic,除非有真正的异常情况发生,即使那样也不应该是我去处理它。而panic和recover是针对自己开发package里面实现的逻辑,针对一些特殊情况来设计。

golang网站错误处理相关推荐

  1. call stack是什么错误_Go语言(golang)的错误(error)处理的推荐方案

    原文链接:https://www.flysnow.org/2019/01/01/golang-error-handle-suggestion.html 微信公众号:flysnow_org(飞雪无情) ...

  2. Go 学习推荐 —(Go by example 中文版、Go 构建 Web 应用、Go 学习笔记、Golang常见错误、Go 语言四十二章经、Go 语言高级编程)

    Go by example 中文版 Go 构建 Web 应用 Go 学习笔记:无痕 Go 标准库中文文档 Golang开发新手常犯的50个错误 50 Shades of Go: Traps, Gotc ...

  3. golang编译错误 copying /tmp/go-build069786374/b001/exe/a.out: No such file or directory 解决方法

    问题: linux虚拟机 golang编译 报错 copying /tmp/go-build069786374/b001/exe/a.out: No such file or directory 原因 ...

  4. 网站服务器上加入三层开发的网站错误解决

    在网站服务器上添加三层开发的网站,发现网站打开的时候提示Server Error in '/' Application.截图如下 解决办法: 1,把文件夹中的bin文件夹移动到上一目录下,比如放入该文 ...

  5. 谷歌网站错误服务器连接,谷歌浏览器 您的链接存在安全隐患 此网站是用的安全配置已过时...---服务器 TLS1.0 1TLS.2配置方法...

    症状: Windows 2008,IIS7,已启用HTTPS. 上周重启了图片服务器,然后陆续有用户反馈浏览器不显示图片,短短几天时间,反馈的人竟陆续多了起来,所以最开始就跑偏了,以为是重启导致的. ...

  6. golang 编译错误:unknown revision xxx

    go mod处理第三方依赖包时出现unknown revision xxx错误. 原因:github上面的一些开源组件,用的git版本是最新的版本. 而编辑机的git版本比较旧,有的git命令没有,导 ...

  7. 网站错误记录:A transport-level error has occurred when sending the request to the server.

    今天查看公司项目的日志文件,发现有这个错误:A transport-level error has occurred when sending the request to the server. 感 ...

  8. golang mysql 错误 sql: unknown driver “mysql“ (forgotten import?) 解决方法

    golang中使用gorm连接mysql的时候会报错:sql: unknown driver "mysql" (forgotten import?) 需要在连接数据库的文件中引入  ...

  9. Golang之错误处理

    1.错误只在逻辑的最外层处理一次,底层只返回错误. 2.底层除了返回错误外,要对原始错误进行包装,增加错误信息.调用栈等这些有利于排查的上下文信息. 1.errors包: //只附加新的信息 func ...

最新文章

  1. 模式主节点ORACLE DG介绍(物理无实例)
  2. 移动开发day1_过渡_2d转换_3d立体
  3. AOS V0.8 发布,JavaEE 应用基础平台
  4. 诗与远方:无题(八)
  5. session和cookie_JSP学习
  6. SSM框架笔记14:Spring MVC表单验证
  7. python scrapy框架基如何实现多线程_Python多线程爬图Scrapy框架爬图
  8. Delphi判断是否有全屏程序
  9. OpenCV入门知识[转载]
  10. 计算机网络原理之运输层
  11. 论文导读:DINO -自监督视觉Transformers
  12. Mysql 统计每周,半个月的数据
  13. TestBird《2021中国手游测试白皮书》---海外手游
  14. Mysql窗口函数 (知识点梳理+题目解析+面试实战)(四万字长文,一文读懂,建议收藏后食用)
  15. 简约大方的HTML表格样式
  16. 学习笔记1:搭建floodlight+mininet+sflow环境
  17. 云笔记的使用感受和选择
  18. [SCOI2010]传送带
  19. 引用 oem 和主板bios修改方法
  20. Ubuntu下HP LaserJet 1000打印机的安装步骤

热门文章

  1. 【错误记录】Flutter 应用运行卡在 Running Gradle task ‘assembleDebug‘... ( 配置阿里云 Maven 仓库镜像 )
  2. 【组合数学】计数模型、常见组合数与组合恒等式 ★★
  3. 【Android RTMP】RTMPDump 封装 RTMPPacket 数据包 ( 关键帧数据格式 | 非关键帧数据格式 | x264 编码后的数据处理 | 封装 H.264 视频数据帧 )
  4. 【Android 应用开发】View 与 SurfaceView 区别
  5. [Spring cloud 一步步实现广告系统] 10. 使用Ribbon 实现微服务调用
  6. p1209 Barn Repair
  7. iframe子页面点击按钮,执行父页面的点击事件
  8. ie下LI的间距问题
  9. 【译文】Web Farm和Web Garden的区别?
  10. 学习 Spring (十三) AOP 配置