本文作者结合实际工作中的一些应用经验,来全面解析一下防御性编程。
成都创新互联公司专注于阿拉尔企业网站建设,成都响应式网站建设公司,商城建设。阿拉尔网站建设公司,为阿拉尔等地区提供建站服务。全流程按需制作网站,专业设计,全程项目跟踪,成都创新互联公司专业和态度为您提供的服务
本文主要内容:
关于防御性编程,这一概念开始来自于汽车的防御性驾驶技术,意为你永远无法确定另一位司机将要做什么,才能确保他人做出危险动作时不会伤害到你。
防御性编程应用过程中,并不是指让你从保护自身,对他人持有“批判或攻击”的态度,而是将保护的意识落地到自身程序上,通过一些防御手段让你的代码程序不因传入的错误数据而出错崩溃。大家通常会说,“代码有问题很正常的呀”,的确是这样,那更应该在编写程序的时候提高防御性的重要性,尤其核心程序能力,做好程序错误影响的包容性。
随着目前互联网已渗透到各行各业,每个细微的风险问题都可能会被放大,足以影响整个行业。
系统服务的稳定性对于企业来说非常重要,不仅仅会对企业带来直接的经济损失,甚至会对行业、人们的生活造成非常严重的影响。
在学习编码的时候,估计大家都听过“不要相信用户的输入”,指的就是对用户输入做检查的必要性。谈到输入,常见Web开发主要包括以下两个方面:
在系统建设过程中,我们经常会需要跟外部系统做数据交互处理,这里包括:文件、接口、消息队列、表单用户输入等等,对于来自系统外部输入的数据内容,我们需要明确做到:
对数据做预期准确性检查,保证输入数据在我们程序的可接受范围以内。其实,所有的安全问题的本质都是信任的问题。数据检查,这个跟车站、机场的安全检查相似。通过一个安全检查(过滤,净化)的过程,可以梳理未知的人或物,使其变得可信任。被划分出来的具有不同信任级别的区域,我们称为信任域,划分两个不同信任域之间的边界,我们称之为信任边界。对于异常数据处理情况,做好防御检查的,同时需要做好日志记录,以防追后账呢,哈哈~
对于系统内部接口API请求,需要检查程序的输入参数的值。这个跟检查来自外部系统的数据一样。
/**
* 请求处理通用类
**/
public class CommonRequest {
@NotBlank(message="参数str不能为空")
private String str;
@NotNull(message = "参数i不能为空")
private Integer i;
@Min(value =0,message = "最小值不能小于0")
private int min;
@Max(value=100,message = "最大值不能大约100")
private int max;
}
通常情况下,需要验证如下几项:
对于接口参数/字段异常情况,大家可以按照以下思路来验证问题:
注意:补充一个关键情况,需要结合业务场景来评估可能的影响范围。
必要情况,设置白名单而不是黑名单。
举个栗子,在你设置图像扩展名的时候,不要设置无效的类型,而是检查有效的类型并排除其他类型。在 PHP 有无数的开源校验库,让你的工作更简单。
要记住:进攻是最好的防守。总而言之,不要将代码外部的函数调用或方法调用想得太过美好。请确保你调用外部的API和库之前理解并测试了错误。
所谓断言,是指在开发期间使用的,让程序在运行时进行自检的代码。通常是一个子程序或者宏。
断言的目的为了表示与验证软件开发者预期的结果,当程序执行到断言的位置时,对应的断言应该为真;若断言不为真时,程序会中止执行,并给出错误信息。
举个例子:
如果系统假定一份数据信息文件所包含的记录数不超过20000,那么程序中可以设置一个断定记录数<=20000 的断言。只要 记录数<= 20000,这一断言都不会触发,然而一旦记录数超过20000,它就会断言程序存在一个错误。
断言可以有两种形式:
其中 Expression1 应该总是一个布尔值,Expression2是断言失败时输出的失败消息的字符串。
如果Expression1为假,则抛出一个 AssertionError,这是一个错误,而不是一个异常,也就是说是一个不可控制异常(unchecked Exception),AssertionError由于是错误,所以可以不捕获,但不推荐这样做,因为那样会使你的系统进入不稳定状态。
public class TestAssert{undefined
public static void main(String[] args){undefined
String name = "abner chai";
//String name = null;
assert (name!=null):"变量name为空null";
System.out.println(name);
}
}
根据前面的介绍,断言可以用于处理代码中不应该发生的错误,那又该如何处理那些预料中可能要发生的错误呢?
异常和错误处理是防御性编程的一个组成部分。
想象一下,启动了一个异步操作,运行并输出结果,没有异常,这是一个理想的情况。如果在执行过程中发生错误怎么办?与任何未处理的异常一样,应用程序通常会崩溃。假设任何异步操作都会成功运行而没有任何错误,那么可能会失败。
高级语言中一般会采用try catch方式捕获异常处理,如下示例:
try {
//逻辑代码
} catch (exception e){
//异常处理代码
}
try{
//逻辑代码
} finally {
//一定要执行的代码
}
try {
//逻辑代码
} catch (exception e){
//异常处理代码
} finally{
//一定要执行的代码
}
而Golang的错误处理规范也是Go语言的最大亮点之一。
标准库把error定义为接口类型, 以便于自己定义错误类型。
type error interface{
Error() string
}
golang的内置方法,能够改变程序的控制流。当函数调用了panic,函数会停止运行,但是defer函数会运行,程序会在当前panic的goroutine全部退栈以后crash。
recover也是golang的内置方法,用于恢复发生panic的goroutine的控制,recover只在defer函数中生效。如果当前goroutine将要发生panic的话, recover会捕获这个panic,并恢复正常执行。
聊到panic和recover,需要聊聊defer这个关键字,后面会看到defer在异常处理机制中起到的作用。go的defer是用来延迟执行函数的,延迟的发生是在调用函数的returen之后。
所谓隔离,是指程序可以包容由错误造成的损害,称为一种容损策略。这个在软件行业中最常见的方案,就是多机房建设。实现服务双机房部署建设,承受单机房故障,保障用户体验。这个实现的难点主要有如下三点:
各个大厂对于核心服务多机房部署的实现,简单列举以下几种实现方案:
基于地理位置单元化,不同服务集群间双向数据复制,内部调用路由。
MySQL多机房同步(写入时写但机房,有专门的组件负责同步写入到另一个机房)。
隔离的应用,同时体现了在架构设计上规定应该如何应用如何处理错误的价值。
在防御性编程的路上,没有银弹。在产品中保留过多的防御性代码,则会与精简代码实现产生相矛盾的地方。从产品本身出发,在不影响用户体验的使用的情况下,使程序能够稳定的运行,梳理了如下几项建议:
其实,对于防御性编程,我们其实是要在保障程序稳定和程序不过于臃肿之间找到一个合理的平衡。防御式编程技术可以让错误更容易发现,更容易修改,并减少错误对代码的破坏,断言可以帮助人们更早的发现错误,关于如何处理错误输入的决策是一项关键的错误处理决策,也是一项关键的高层设计决策。防范看似微小的错误,收益价值可能远远超出你的想象。
网站栏目:关于防御性编程,你应该知道的事
标题URL:http://www.shufengxianlan.com/qtweb/news17/199517.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联