WebApi学习纪要
WebApi介绍
- 微软的web api是完全基于RESTful标准的,完全不同于之前的(同是SOAP协议的)wcf和webService;
- RESTful是一种网络应用程序的设计风格和开发方式,基于HTTP,可以使用XML格式定义或JSON格式定义,REST:Representational State Transfer(表象层状态转变),难懂!
特性路由
- 将RouteAttribute或自定义继承自RouteAttribute的特性类标记在控制器或ACTION上,同时指定路由Url字符串,从而实现路由映射,相比之前的通过Routes.Add或Routes.MapHttpRoute来讲,更加灵活与直观,若要使用特性路由功能需要先在
WebApiConfig.Register
注册:config.MapHttpAttributeRoutes();
或者在Application_Start里注册GlobalConfiguration.Configuration.MapHttpAttributeRoutes();
:
1.基本路由映射:[Route("api/Values")]=>http://localhost:34732/api/values
2.路由映射到参数:[Route("api/Values/{id}")]=>http://localhost:34732/api/values/11
3.多重特性路由:[Route("api/Values/{value1}/{value2}")] [Route("api/Demo/{value2}/{value1}")]
4.缺省(默认)参数路由:[Route("api/Values/option/{key}/{value?}")]=>http://localhost:34732/api/Values/option/a
4.缺省(默认)参数路由:[Route("api/Values/option/{key}/{value=test}")]=>http://localhost:34732/api/Values/option/a/api
5.参数约束路由:[Route("api/Values/constraint/{id:range(1,10)}")]=>http://localhost:34732/api/Values/constraint/10
- 也可以修改路由匹配规则,按mvc方法匹配路由(有action匹配);
好的api设计要点
- URI、查询参数、HTTP方法、响应数据格式、出错信息、版本管理等:参考来源:如何设计出优美的Web API?
- URI
- 简短不冗余
- 反例:http://api.example.com/service/api/users
- 正例:http://api.example.com/users
- 容易读懂的URI,不要随意采用缩写,x,y
- 反例:http://api.example.com/x/y
- 不要大小写混用的URI
- 命名存在可预见的规律,改变最后的ID就可以访问其他商品的信息
- 正例:http://api.example.com/v1/items/123456
- 不会暴露服务端架构的URI
- 反例:http://api.example.com/cgi-bin/get_user.php?user=100
- 命名,参数规则统一的URI,比如要么采用查询参数或者要么采用了路径参数
- 查询参数:http://api.example.com/friends?id=100,如果该属性可以省略,那么它就是适合作为查询参数
- 路径参数:http://api.example.com/friends/100,如果该属性信息可以唯一定位资源,那么它就适合作为路径构成元素
- URI最好由名词组成
- 不使用空格及需要编码的字符,例如在URI中使用中文等
- 查询参数
- per-page与page风格:http://api.example.com/friends?per-page=50&page=3
- limit与offset风格:http://api.example.com/friends?limit=50&offset=100
- 完全符合,过滤参数的名称通常为属性名:http://api.example.com/v1/users?name=ken
- 全文搜索,查询结果任意属性部分包含过滤参数的取值,那过滤参数的名称通常为“q”:http://api.example.com/v1/users?q=ken
- HTTP方法,表示对资源的操作方法:
- GET,获取资源
- POST,新增资源
- PUT,更新已有资源
- DELETE,删除资源
- PATCH,更新部分资源
- HEAD,获取资源的元信息
- 出错信息http状态码
- 1XX:消息
- 100 Continue,如post请求分2次,第1次建立连接,服务器返回100,客户端将数据post到服务器
- 2XX:成功
- 200 OK,对应http方法:get、put、patch返回
- 201 Created,对应http方法:post
- 204 No Content,对应http方法:delete
- 3XX:重定向
- 304 Not Modified
- 4XX:客户端原因引起的错误
- 400 Bad Request,请求数据校验错误
- 401 Unauthorized账户验证错误
- 403 Forbidden权限不足
- 404 Not Found找不到资源
- 5XX:服务器端原因引起的错误
- 500 Internal Server Error服务器端的源代码出现错误
- 502 Bad Gateway
- 503 Service Unavailable服务器维护或者过载
- 504 Gateway Timeout
- 1XX:消息
- 版本管理
- 在URI中嵌入版本编号,示例:http://api.linkedin.com/v1/people
- 在查询字符串里加入版本信息,示例:http://api.example.com/users/123?v=2
- 通过媒体类型来指定版本信息,Accept: application/vnd.github.v3+json;Content-Type: application/vnd.github.v3+json
常用特性、过滤器应用
- 过滤器是利用AOP实现的;
- 权限特性
AuthorizeAttribute
,新增一个类,继承AuthorizeAttribute
,重写OnAuthorization
虚方法,然后在控制器或方法上新增此特性,相应的有个AllowAnonymousAttribute
特性,可以避免权限验证;
//新增一个类,继承`AuthorizeAttribute`
public class MyBasicAuthorizeAttribute : AuthorizeAttribute
{
//有 AllowAnonymousAttribute 特性的,无需进行权限验证
if (actionContext.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>(true).Count != 0
|| actionContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes<AllowAnonymousAttribute>(true).Count != 0)
{
base.OnAuthorization(actionContext);//执行真实逻辑
}
else
if(请求头里有Ticket或者cookie里有Ticket,进行用户验证逻辑)
{
base.IsAuthorized(actionContext); //如果成功,执行真实逻辑
}
else
{
this.HandleUnauthorizedRequest(actionContext);//没有权限
}
}
- 异常处理特性
ExceptionFilterAttribute
,同样新增一个类,继承ExceptionFilterAttribute
,重写OnException
虚方法,因为是异常处理,建议全局生效,故在WebApiConfig.Register
里注册(非FilterConfig.RegisterGlobalFilters(),这个是针对mvc的),而不是只修饰部分类,另外不能捕获控制器实例化和路径错误的异常,如果要捕获,则需继承ExceptionHandler
类而不是ExceptionFilterAttribute
;
//异常过滤器
public class MyExceptionAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
}
}
//在WebApiConfig.Register里注册
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
//异常处理注册,全局生效
config.Filters.Add(new MyExceptionAttribute());
// Web API 配置和服务
// Web API 路由
}
}
- 方法过滤特性,继承
ActionFilterAttribute
类,重写OnActionExecuting
(方法执行前)和OnActionExecuted
(方法执行后),比如执行方法后,在response里加入允许跨域的响应头信息actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");
public class CustomActionFilterAttribute : ActionFilterAttribute
{
/// <summary>
/// 方法执行前
/// </summary>
/// <param name="actionContext"></param>
public override void OnActionExecuting(HttpActionContext actionContext)
{
//处理逻辑
}
/// <summary>
/// 方法执行后
/// </summary>
/// <param name="actionExecutedContext"></param>
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
//处理逻辑
//允许跨域
actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");
base.OnActionExecuted(actionExecutedContext);
}
}