1.导言

路由系统是请求消息进入http://ASP.NET Web API消息处理管道的第一道屏障,其根本目的在于利用注册的路由对请求的URL进行解析以确定目标HTTPController和Action的名称,以及与目标Action方法某个参数进行绑定的路由变量。

WebService和WCF的协议都是soap协议,数据的序列化和反序列化都是soap的格式。而WebAPI是基于Http协议,请求和返回格式结果默认是 json格式,因此,比WCF更简单、更通用,比 WebService 更节省流量、更简洁。 Web API是在.NET Framework上构建RESTful应用程序的理想平台,为了更清楚弄懂WebAPI的路由配置,我们首先要了解HTTP协议和RESTful架构风格。

2.HTTP协议

HTTP协议(HyperText Transfer Protocol,超文本传输协议)是因特网上应用最为广泛的一种网络传输协议,所有的WWW文件都必须遵守这个标准。我们在这里紧列举和本文关系密切的HTTP请求方法和HTTP状态码。

2.1 HTTP请求方法

根据HTTP标准,HTTP请求可以使用多种请求方法。

begin{array}[b] {|c|c|}
hline 对象 & 对象名称& 对象类型
hline cin & 标准输入(standard input) & istream
hline cout & 标准输出(standard output)& ostream
hline cerr & 标准错误(standard error)& ostream
hline clog & 输出一般性信息 & ostream hline
end{array}

HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法,HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法,如下表所示:

序号|方法|描述 ---|:--:|--- 1| GET |请求指定的页面信息,并返回实体主体。 2| HEAD| 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头 3| POST| 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。 4| PUT| 从客户端向服务器传送的数据取代指定的文档的内容。 5| DELETE| 请求服务器删除指定的页面。 6| CONNECT| HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。 7| OPTIONS| 允许客户端查看服务器的性能。 8| TRACE| 回显服务器收到的请求,主要用于测试或诊断。

2.2 HTTP状态码

当浏览者访问一个网页时,浏览者的浏览器会向网页所在服务器发出请求。当浏览器接收并显示网页前,此网页所在的服务器会返回一个包含HTTP状态码(HTTP Status Code)的信息头(server header)用以响应浏览器的请求。

常见的HTTP状态码如下表:

状态码| 状态码英文名称| 中文描述

---|:---:|---

200| OK| 请求成功。一般用于GET与POST请求

301| Moved Permanently| 永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替

404| Not Found| 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面

500| Internal Server Error| 服务器内部错误,无法完成请求

3.RESTful介绍

在介绍RESTful之前,我们需了解什么REST,他有那些特征,以及REST成熟度模型。

3.1 REST介绍

REST是Representational State Transfer的缩写,翻译为表象化状态转变或表述性状态转变,是Roy Fielding博士在2000年他的博士论文中提出来的一种软件架构风格,它包含了一个分布式超文本系统中对于组件、连接器和数据的约束。REST 是作为互联网自身架构的抽象而出现的,其关键在于所定义的架构上的各种约束。只有满足这些约束,才能称之为符合 REST 架构风格。

3.2 REST系统的特征

RESR系统包括6个特征,如下所示:

  • 客户端-服务器结构(Client-Server)
    通过一个统一的接口来分开客户端和服务器,使得两者可以独立开发和演化。客户端的实现可以简化,而服务器可以更容易的满足可伸缩性的要求;
  • 无状态(Stateless)
    在不同的客户端请求之间,服务器并不保存客户端相关的上下文状态信息。任何客户端发出的每个请求都包含了服务器处理该请求所需的全部信息;
  • 可缓存(Cachable)
    客户端可以缓存服务器返回的响应结果。服务器可以定义响应结果的缓存设置。
  • 分层的系统(Layered System)
    在分层的系统中,可能有中间服务器来处理安全策略和缓存等相关问题,以提高系统的可伸缩性。客户端并不需要了解中间的这些层次的细节。
  • 按需代码(Code-On-Demand,可选)
    服务器可以通过传输可执行代码的方式来扩展或自定义客户端的行为。这是一个可选的约束。
  • 统一接口(Uniform Interface)
    该约束是 REST 服务的基础,是客户端和服务器之间的桥梁。该约束又包含下面 4 个子约束。
  • 资源标识符:每个资源都有各自的标识符。客户端在请求时需要指定该标识符。在 REST 服务中,该标识符通常是 URI。客户端所获取的是资源的表达(representation),通常使用 XML 或 JSON 格式。
  • 通过资源的表达来操纵资源:客户端根据所得到的资源的表达中包含的信息来了解如何操纵资源,比如对资源进行修改或删除。
  • 自描述的消息:每条消息都包含足够的信息来描述如何处理该消息。
  • 超媒体作为应用状态的引擎(HATEOAS):客户端通过服务器提供的超媒体内容中动态提供的动作来进行状态转换。、

3.3 REST成熟度模型

Richardson 提出的 REST 成熟度模型。该模型把 REST 服务按照成熟度划分成 4 个层次,我们常用到的就是Level1和Level2,如下图所:

具体说明如下:

  • Level 0:Web 服务只是使用 HTTP 作为传输方式,实际上只是远程方法调用(RPC)的一种具体形式。SOAP 和 XML-RPC 都属于此类。
  • Level 1:Web 服务引入了资源的概念。每个资源有对应的标识符和表达。
  • Level 2:Web 服务使用不同的 HTTP 方法来进行不同的操作,并且使用 HTTP 状态码来表示不同的结果。如 HTTP GET 方法来获取资源,HTTP DELETE 方法来删除资源。
  • Level 3:Web 服务使用 HATEOAS。在资源的表达中包含了链接信息。客户端可以根据链接来发现可以执行的动作。例如,客户端通过订单资源中包含的链接取消某一订单,GET 请求被发送去获取该订单。HATEOAS 的优点包括无需在客户端代码中写入硬链接的 URL。此外,由于资源信息中包含可允许操作的链接,客户端无需猜测在资源的当前状态下执行何种操作。

3.4 RESTful

RESTful是一种常见的REST应用,是遵循REST风格的web服务,REST式的web服务是一种ROA(面向资源的架构)。

RESTful资源操作如下表:

http方法| 资源操作| 幂等 |安全

:---:|:---:|:---:|---

GET| SELECT| 是| 是

POST| INSERT| 否| 否

PUT| UPDATE| 是| 否

DELETE| DELETE| 是| 否

注:幂等性:对同一REST接口的多次访问,得到的资源状态是相同的;安全性:对该REST接口访问,不会使服务器端资源的状态发生改变。

RESTful URL请求格式与传统请求格式比较如下表所示:

传统URL请求格式| RESTFul请求格式| 描述

---|---|:---

http:/localhost/user/query/1 GET| http:/localhost/user/1 GET| 根据用户id查询用户数据

http:/localhost/user/save POST| http:/localhost/user POST| 新增用户 http:/localhost/user/update POST| http:/localhost/user PUT| 修改用户信息 http:/localhost/user/delete GET/POST| http:/localhost/user DELETE| 删除用户信息

4.Web API路由

路由的目的是用于解析请求的URL来确定Controller和Action。Web API默认路由是通过http的方法(get/post/put/delete)去匹配对应的action,也就是说webapi的默认路由并不需要指定action的名称,当然,WebApi也支持MVC里面的路由机制,但RestFul风格的服务要求请求的url里面不能包含action,所以,在WebApi里面是并不提倡使用MVC路由机制的。下边通过例子介绍Web API路由原理以及使用。

4.1 新建空的Web API应用程序

上篇博客介绍了手动搭建基本框架,这次我们通过VS2017提供的模板,新建空的WebAPI应用程序MyWebAPI2,构建过程中仅勾选Web API,如下图所示。

创建完成,应用程序的目录结构如下图所示。

4.2 默认路由

App_Start文件夹下WebApiConfig.cs类用于注册Web API路由,默认路由代码如下:

public static void Register(HttpConfiguration config)
{//默认路由config.Routes.MapHttpRoute(name: "DefaultApi",routeTemplate: "api/{controller}/{id}",defaults: new { id = RouteParameter.Optional });
}

在Models文件夹增加一个Student类,代码如下:

public class Student
{public string Id { get; set; }public string Name { get; set; }public string Sex { get; set; }public int Age { get; set; }public string Dept { get; set; }
}

在Controllers文件夹中添加一个Web API控制类(v2.1),命名为StudentController,并修改相关代码,如下所示:

public class StudentController : ApiController
{private static List<Student> studentList = new List<Student>(){new Student() {Id = "001", Name = "张三", Sex = "男", Age = 19, Dept = "软件学院"},new Student() {Id = "002", Name = "李丽", Sex = "女", Age = 19, Dept = "资环学院"}};[HttpGet]public IEnumerable<Student> Get(){return studentList;}[HttpGet]public Student Get(string id){List<Student> tempList = studentList.Where(p => p.Id == id).ToList();return tempList.Count==1?tempList.First():null ;}[HttpPost]public bool Post([FromBody]Student student){if (student == null) return false;if (studentList.Where(p=>p.Id==student.Id).ToList().Count>0) return false;studentList.Add(student);return true;}[HttpPut]public bool Put(string id, [FromBody]Student student){if (student == null) return false;List<Student> tempList = studentList.Where(p => p.Id == id).ToList();if (tempList.Count == 0) return false;Student originStudent = tempList[0];originStudent.Name = student.Name;originStudent.Sex = student.Sex;originStudent.Age = student.Age;originStudent.Dept = student.Dept;return true;}[HttpDelete]public bool Delete(string id){List<Student> tempList = studentList.Where(p => p.Id == id).ToList();if (tempList.Count == 0) return false;studentList.Remove(tempList[0]);return true;}
}

在实际项目中,增删改查这些操作都是和数据库打交道的,这里为了演示具体实现,用一个静态数组存储数据。运行程序,我们采用Fiddler工具进行测试调用。

测试一:调用Get()方法

功能说明:通过路由解析StudentController中的Get()Action,获取所有学生列表。

URL:http://localhost:52317/api/student;HTTP方法:GET。如下图所示:

测试结果:HTTP状态码为200,获取的JSON数据如下所示:

测试二:调用Get(string id)方法

功能说明:通过路由解析StudentController中的Get(string id)Action,根据学号获取某个学生信息。

URL:http://localhost:52317/api/student/002;HTTP方法:GET

测试结果:HTTP状态码为200,获取的JSON数据如下所示:

测试三:调用Post([FromBody]Student student)方法

功能说明:通过路由解析StudentController中的Post([FromBody]Student student)Action,插入一条数据,其中参数前添加[FromBody]是指该参数不是从URL中获取,而是在RequestBody中获取。

URL:http://localhost:52317/api/student;HTTP方法:POST。在RequestBody输入Json格式的数据,如下图所示:

测试结果:HTTP状态码为200,返回的数据TRUE。重复测试一,获取所有学生列表如下图所示。

测试四:调用Put(string id, [FromBody]Student student)方法

功能说明:通过路由解析StudentController中的Put(string id, [FromBody]Student student)Action,实现通过学号更新信息,其中学号id是在Url中获取。

URL:http://localhost:52317/api/student/002;HTTP方法:PUT

测试结果:HTTP状态码为200,返回的数据TRUE。

测试五:调用Delete(string id)方法

功能说明:通过路由解析StudentController中的Delete(string id)Action,删除某学生信息,其中学号id是在Url中获取。

URL:http://localhost:52317/api/student/002;HTTP方法:DELETE

测试结果:HTTP状态码为200,返回的数据TRUE。

总结:通过上边测试,我们可以到URL中没有用到Action,默认路由就是通过参数和HTTP方法匹配Controller中的Action。

4.3 自定义路由

在实际项目中,如果http请求的类型相同,且请求参数相同(如Get),这个时候按照默认路由肯定会出问题,具体出现什么问题,我们在这做个测试:

在StudentController中添加一个Action,用于查询某个学院的所有同学,代码如下:

[HttpGet]
public IEnumerable<Student> GetByDept(string id)
{List<Student> tempList = studentList.Where(p => p.Dept == id).ToList();return tempList;
}

这时,运行程序,输入URL:http://localhost:52317/api/student/资环学院;HTTP方法:GET。测试结果发现返回的结果null,跟踪测试代码发现该URL调用的Get(string id)这个Action。

那么问题就来了,怎么才能调用这个Action呢?其中有两种方法一种是自定义路由,就像MVC那样在模板中增加Action,另一种为通过Web API路由特性实现。

在App_Start文件夹下WebApiConfig.cs类中添加ActionAPI路由模板,代码如下:

public static void Register(HttpConfiguration config)
{//默认路由config.Routes.MapHttpRoute(name: "DefaultApi",routeTemplate: "api/{controller}/{id}",defaults: new { id = RouteParameter.Optional });//自定义路由config.Routes.MapHttpRoute(name: "ActionApi",routeTemplate: "api/{controller}/{action}/{id}",defaults: new { id = RouteParameter.Optional });}

运行程序,输入URL:http://localhost:52317/api/student/GetByDept/资环学院;HTTP方法:GET。运行结果如下:

注:若出现中文乱码,解决途径请参考Fiddler抓包中文乱码问题。

由此可知通过自定义路由可以解决该问题,但是不符合RESTful风格,所有不提倡使用该方法。

4.4 特性路由

默认路由解决不了的访问,可以通过Web API的路由特性解决。

启动路由特性:在App_Start文件夹下WebApiConfig.cs类中启用特性路由,代码如下:

public static void Register(HttpConfiguration config)
{//启用Web API特性路由config.MapHttpAttributeRoutes();//默认路由config.Routes.MapHttpRoute(name: "DefaultApi",routeTemplate: "api/{controller}/{id}",defaults: new { id = RouteParameter.Optional });//自定义路由config.Routes.MapHttpRoute(name: "ActionApi",routeTemplate: "api/{controller}/{action}/{id}",defaults: new { id = RouteParameter.Optional });
}

修改StudentController中GetByDept代码如下:

[Route("student/GetByDept/{dept}")]
[HttpGet]
public IEnumerable<Student> GetByDept(string dept)
{List<Student> tempList = studentList.Where(p => p.Dept == dept).ToList();return tempList;
}

运行程序,输入URL:http://localhost:52317/student/GetByDept/软件学院;HTTP方法:GET。运行结果如下:

通过此例,可以看到Web API特性路由非常灵活方便,具体使用要结合实际项目灵活运用。

5. 总结

本文在开始部分介绍了HTTP协议及RESTful架构风格,让我们更深入的了解Web API的设计初衷,又通过实际的例子(文中的代码及结果均通过了测试),让我们掌握了路由配置的各种方法。文中若有不足之处,还望海涵,博文写作不易希望多多支持,后续会更新更多内容,感兴趣的朋友可以加关注,欢迎留言交流!

扫描添加下方的微信公众号,获取更多福利和干货!也可通公众号(码探长)联系探长,期待与你相遇!!!

微信公众号

webapi 设置参数可为空_Web API系列(二):灵活多样的路由配置相关推荐

  1. Web API系列(三):添加接口详细说明及测试

    1.引言 前边两篇博客介绍了Web API的基本框架以及路由配置,这篇博客主要解决在前后端分离项目中,为前端人员提供详细接口说明的问题,主要是通过修改WebApi HelpPage相关代码和添加Web ...

  2. 如何使 WebAPI 自动生成漂亮又实用在线API文档

    1.前言 1.1 SwaggerUI SwaggerUI 是一个简单的Restful API 测试和文档工具.简单.漂亮.易用(官方demo).通过读取JSON 配置显示API. 项目本身仅仅也只依赖 ...

  3. Polyworks脚本开发学习笔记(十一)-玩转获取参数(GET)与设置参数

    Polyworks脚本开发学习笔记(十一)-玩转获取参数(GET)与设置参数 Polyworks采用了脚本语言作为二次开发的工具,因此语言格式上非常规范和统一.其中一个重要的特点就是,几乎所有的对象都 ...

  4. WEB API 系列(二) Filter的使用以及执行顺序

    在WEB Api中,引入了面向切面编程(AOP)的思想,在某些特定的位置可以插入特定的Filter进行过程拦截处理.引入了这一机制可以更好地践行DRY(Don't Repeat Yourself)思想 ...

  5. Web API系列(三)统一异常处理

    前面讲了webapi的安全验证和参数安全,不清楚的朋友,可以看看前面的文章,<Web API系列(二)接口安全和参数校验>,本文主要介绍Web API异常结果的处理.作为内部或者是对外提供 ...

  6. pandas使用read_csv函数读取文件时指定数据列的数据类型、pandas使用read_csv函数读取文件时通过keep_default_na参数设置缺失值替换为空字符串

    pandas使用read_csv函数读取文件时指定数据列的数据类型.pandas使用read_csv函数读取文件时通过keep_default_na参数设置缺失值替换为空字符串 目录

  7. url传递参数时,设置参数可以传值为空

    设置最后一个参数groupName可以传值或为空 一.前端传值方式: 使用: if (this.searchgroupinfo === "" || this.searchgroup ...

  8. C#进阶系列——WebApi 接口参数不再困惑:传参详解

    看这边文章时的疑惑是:WebApi中的参数加了[FromBody],不知所以然,就百度了下,看到了以下文章,和大家分享下: 原文链接:http://www.cnblogs.com/landeanfen ...

  9. WebApi 接口参数不再困惑:传参详解

    阅读目录 一.get请求 1.基础类型参数 2.实体作为参数 3.数组作为参数 4."怪异"的get请求 二.post请求 1.基础类型参数 2.实体作为参数 3.数组作为参数 4 ...

最新文章

  1. 是什么造成了网管员的低工资?
  2. oauth2_带有Spring Security的OAuth 2.0快速指南
  3. matlab6.0序列号,MFC软件获取USB设备的制造商、产品、序列号
  4. 2014北科计算机原理试题答案,北科_计算机组成原理考题-A卷答案
  5. Python中利用LSTM模型进行时间序列预测分析
  6. U-GAT-IT整体流程分析
  7. 用matlab绘制P三曲线,知道曲线方程 怎么用matlab绘制三维图 一定要给出程序 , matlab怎样画三维曲线...
  8. ubuntu未发现wifi适配器_Windows 10 9月更新频翻车,1903版本网络适配器又出bug
  9. Tensorflow:模型调参
  10. android第一行代码-6.自定义控件的实现
  11. unity3dk帧_Unity3D制作序列帧动画的方法
  12. iOS 使用iPhone配置实用工具 创建桌面快捷方式
  13. JavaScript基础用法
  14. cmd与服务器文件传输,渗透技巧--通过cmd上传文件的N种方法
  15. 如何下载免费版的PDF编辑器
  16. 别了,AlphaGo之魂——黄士杰
  17. CO BW成本报表建立小结
  18. IDAE Keystore was tampered with报错解决
  19. VMWARE虚拟机网络环境配置
  20. 子集生成算法 之 位向量法和增量构造法

热门文章

  1. 《学习javascript数据结构与算法》——第六章:集合
  2. 某集网将我的信息给了谁?还是不良卖家不想卖东西
  3. jsp 静态资源 打入jar
  4. Linux命令find查询suid和sgid
  5. 关于用隐藏文字(图片替换文字)的更好的可用性方法
  6. spring实现事务原理
  7. Alpha冲刺 - (4/10)
  8. 爬虫-性能相关- twisted-tornado
  9. docker的介绍和常用命令
  10. Java学习笔记20(String类应用、StringBuffer类、StringBuilder类)