Skip to content

如何生成错误响应

zhangjin edited this page Mar 4, 2015 · 8 revisions

一个Api服务在正常的情况下,会返回正确的响应,但是有很多情况可能造成服务无法正确处理,如:

  • 请求的参数不合法
  • 服务资源不可用
  • 权限或安全原因不可访问 等等

由于客户端只能根据服务端返回的报文,知道究竟发生了什么问题,因此在发生任何异常时,服务端都必须返回一个客户端可识别错误信息,这样,客户端才能进行相应的处理。

开发Web Service Api难的不在于正常情况下的处理,而在于如何处理各种异常的情况返回相应的错误信息。ROP参考TOP(淘宝开放平台)的错误体系,对创建了一个满足灵活、稳定的错误描述体系,开发者仅需要通过这个异常体系,进行相应的实例化就可以了。

ROP会自动处理大多数和错误情况,开发者仅须关系“业务相关”的错误。以下是ROP框架会自动处理的错误:

1.请求的系统级参数的合法性:

如method这个系统参数缺少,不存在sign参数等,ROP会自动驳回请求,返回相应的错误报文。

  <?xml version="1.0" encoding="utf-8" standalone="yes"?>
  <error solution="Missing Method" message="Missing Method" code="26"/>

2.请求的业务级参数不合法:

每一个请求都对应一个Request对象,在该Request类中,可以通过JSR303的注解定义校验规则,如果客户端发送过来的请求数据违反了校验规则,ROP也会产生相应的错误,如:

	<?xml version="1.0" encoding="utf-8" standalone="yes"?>
	<error solution="Invalid Arguments" message="Invalid Arguments " code="34">
		<subErrors>
			<subError>
				<code>isv.parameters-mismatch:salary-and-aaa0</code>
				<message>incoming parameter salary and aaa0 does not match, both have a certain correspondence between</message>
			</subError>
		</subErrors>
	</error>

3.服务开发者要自己处理错误包含两类:

1)业务数据不存在,如根据userId查询User,找不到时可返回NotExistErrorResponse,如

  new NotExistErrorResponse("User", "userId", "123", request.getLocale())

2)业务错误,通过ServiceErrorResponse创建业务错误,如

	@ApiMethod("user.add")
	public RopResponse addUser(CreateUserRequest request) {
		if(reservesUserNames.contains(request.getUserName())){ //如果注册的用户是预留的帐号,则返回错误的报文
			return new ServiceErrorResponse(
					request.getMethod(), USER_NAME_RESERVED,request.getLocale(),request.getUserName());
		}else{
		 ...
		}
	}

如果是返回业务错误,则开发者必须在类路径 的i18n/rop/ropError的资源文件中定义好错误国际化资源信息,如在 rop-sample/src/main/resources/i18n/rop/ropError_en.properties中就添加了一条错误国际化资源信息:

  isv.user-add-service-error\:USER_NAME_RESERVED= {0} is reserved,please choose other user name.

rop-sample/src/main/resources/i18n/rop/ropError_zh_CN.properties的如下所示:

  isv.user-add-service-error\:USER_NAME_RESERVED= {0} 是预留的用户,请选择其它的用户名.

开发者可以通过web.xml中的RopServlet的ropErrorBaseName init-param定义国际化资源所在的位置,默认为i18n/rop/ropError:

	<servlet>
		<servlet-name>rop</servlet-name>
		<servlet-class>
			com.rop.RopServlet
		</servlet-class>
		<init-param>
			<param-name>ropErrorBaseName</param-name>
			<param-value>i18n/rop/serviceError</param-value>
		</init-param>
		<load-on-startup>2</load-on-startup>
	</servlet>

从上,可以看出,基于ROP编写服务的错误响应是非常简单的