ASP.NET Core与RESTful API 开发实战(一)
ASP.NET Core与RESTful API 开发实战(一)
简介
这是一篇《ASP.NET Core与RESTful API 开发实战》的个人读书笔记,如有需要推荐购买正版书籍,详细阅读学习。
REST与HTTP简介
什么是REST
REST 是一种基于资源的架构风格,在REST 中,资源是最基本的概念。任何能够命名的对象都是一个资源,如docuent,user,order等,通常情况下,它表示Web服务中要操作的一个实体。一个资源具有一个统一的资源标识符,如users/1234,通过资源标识符能够表示并访问该资源。
除了单个的资源外,资源集合表示多个相同类型的资源,如uesrs。在系统设计时,不同的实体之间往往存在某种关联关系,如一个用户有多个订单。同样在REST中,这种关联关系也能够由资源之间的层次关系体现出来,如users/1234/orders/1
由于REST以资源为中心,因此REST接口的端点均以资源或资源集合结尾,它不像其他形式的web服务一样以动词结尾,如api/GetUserInfo/或api/UpdateUserInfo.在REST中,对资源的动作或操作时通过HTTP方法来完成的。
REST约束
REST定义了6个架构约束,遵循这些约束的Web服务是真正的RESTful服务,即REST风格的服务。如果一个系统违反了其中的约束,则不能称其为RESTful,这些约束包括如下:
- 客户端-服务器
客户端-服务器约束体现了关注点分离原则。 - 统一接口
统一接口是设计任何RESTful服务的基础,也是区别REST架构风格与其他Web服务风格的最主要约束。系统中的多个组件(包括服务端,客户端,以及可能存在的代理服务器等)都依赖于统一接口。统一接口本身又由4个子约束组成,分别如下:
1. 资源的标识
2. 通过表述操作资源
当请求一个资源时,服务器返回该资源的一个表述。该表述表示资源当前的状态,它由表述正文和表述元数据组成,格式通常为JSON,XML,和HTML等。
3. 自描述信息
客户端与服务器之间传递的每一条消息都应包含足够的信息,这些信息不仅包含了资源的表述,也包含了资源表述的相关信息。(如资源表述的格式与内容长度等),甚至包含了与该资源相关的其他操作信息。
4. 超媒体作为应用程序状态引擎
服务器返回的资源的资源表述中不仅要包含资源的表述,也应包含与之相关的链接,这些链接能够对资源执行其他操作,比如当获取资源时,返回的链接中包含更新该资源,删除该资源等来链接。 - 分层系统
分层系统约束能够使网络中介(如代理或网关等)透明地部署到客户端与服务器之间,只要它们遵循并且使用前面提到的同意接口约束即可;而客户端和服务器则都不知道网络中介的存在,中间服务器主要用于增强安全,负责均衡和相应缓存等目的。 - 缓存
缓存是Web架构中最重构的特性之一。客户端或网络中介均能够缓存服务器返回的响应,因此当服务器返回响应时,应知名该相应的缓存特ing。对相应进行缓存将有助于减少数据获取延迟以及对服务器的请求,从而提高系统的性能。 - 无状态
无状态约束将知名服务器不会记录或储存客户端的状态信息,反之,这些状态信息应由客户端来保存并维护,因此客户端对服务器的请求不能依赖于已发生过的其他请求,当客户端请求服务器时,必须在请求消息中包含所有与之相关的信息(如认证信息等) - 按需编码
按需编码约束允许服务器临时向客户端返回可执行的程序代码(如脚本等,返回这些代码主要用于为客户端提供扩展性或自定义的功能。由于客户端必须理解并能够执行服务器返回的代码,因此这一约束增加了客户端与服务器之间耦合,同时这一约束时可选的。
REST与RPC风格的区别如下:
- 在关注点方面,REST 面向资源,RPC面向功能。
- 在API 端点方面,REST的端点是名词,是资源或资源集合,而RPC的断电时动词,是方法名。
- 在执行特点方面REST对象资源执行操作,RPC执行服务器上的方法
- 在返回结果方面,REST返回请求的资源,而RPC则返回调用方法的执行结果。
HTTP协议
HTTP协议采用了请求/响应模式。当客户端(通常是浏览器)发起一个HTTP请求时,它首先会建立起到HTTP服务器指定端口(HTTP协议默认使用80端口)的TCP连接,而HTTP服务器则负责在该端口监听来自客户端的请求。当TCP连接成功建立后,浏览器就会向HTTP服务器发送请求命令,如GET/indexs.html.HTTP/1.1.一旦收到请求,服务器会根据请求向客户端返回响应,其响应内容通常包括一个状态行(如HTTP/1.1 200 OK)和若干个消息头,以及详细正文。消息正文则是资源、请求的文件、错误或其他信息等。
统一资源定位符
统一资源定位符,即通常所说的URL代表网络上一个特定的资源。URL作为URI的子集,一个URL就是一个URI,用于标识并定位资源。
HTTP://,这一部分时URL协议,URL协议指明了如何访问一个特定的资源,如上例中的http://会告诉浏览器要使用HTTP协议,即超文本传输协议;除了http://外,较为常见的协议还有https:(加密的HTTP协议)、ftp://(文件传输协议)和mailto:(电子邮件协议)等。
WWW.```.COM,这一部分是主机名,主机名会告诉浏览器要访问的资源所在的服务器名称。DNS服务器会将这个名称解析为一个具体的IP地址,通过这个IP地址可以找到资源所在的计算机。
images/logo.png,这一部分是URL路径,它只想服务器上具体的资源。更具要获取资源的不同,其值也会不同,可以说这一部分的变化性最大。他有可能是再服务器中的一个真实存在的文件,比如这里的images/logo.png,也有可能是由常见的Web框架生成的动态资源,如http://www.```.com/account/index.通常请开给你下,当访问某个网页浏览器时,浏览器会下载其他与此相关的资源,如文本信息,图片,js文件,css等,所有这些资源构成了我们再浏览器中看到的页面。
除了上述3个主要 部分外,URL还常常包括以下几个可选的部分
端口号,再主机名后面,以冒号隔开,这一部分通常省略。服务器在这个端口上监听HTTP气你去,因此再请求的URL中必须指定相同的端口,HTTP协议默认使用80端口,80默认省略,非80则需要再URL中知名端口号,如:8080等,但这种情况比较少见,一般只有再开发或者调试Web应用时才会使用其他端口。
查询字符串,URL中“?”后面的参数部分,对于http://www.```com/search?q=helo这样一个URL,“q=hello”即为查询字符串,其中“q”是参数名,“hello”是参数值,参数名和参数用“=”分隔。如果要传递多个参数,则使用&来分割。查询的字符串会发送给HTTP服务器,并由服务器上的Web应用程序决定如何处理这一部分的内容。
锚部分,也称片段,即在“#”后面的内容,它用于指明一个资源的特定位置,例如,http:.//www.```com/index.html#contact,该URL将定位到HTML页面中指定的元素。这一部分内容与上述的其他部分都不一样,它不会由服务器处理,只会由浏览器处理,也就是说,若更改这一部分的内容,并不会向服务器再次发起请求,浏览器就会定位到当前资源的不同位置。
由此可见,一个完整的URL形式如下所示:
😕/ [:port]/[path][?query][#fragment]
媒体类型
如:text/plain、image/gif、audio/midi、video/ogg、application/pdf
HTTP消息
客户端发出请求,服务器响应,请求与响应过程如同“对话”一样,两者使用HTTP协议规定对话格式的消息。HTTP消息证实两者交换数据的方式,它由两种类型:请求消息和响应消息
HTTP请求消息和响应消息具有相似的结构,他们都包括一下4部分的内容。
- 起始行:即第一行,用于描述要执行的请求,或者是对应的转台,即成功或失败,这个起始行总是单行的。
- HTTP消息头:这些消息头描述了请求或响应的相关属性、配置、对消息正文的描述等。
- 空行:指明消息头已经发送完毕
- 消息正文:包含请求数据(如要创建的资源、HTML表单内容等),或响应中资源的表述,这一部分可空。
GET /search?hl=zh-CN&source=hp&q=domety&aq=f&oq= HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint,
application/msword, application/x-silverlight, application/x-shockwave-flash, */*
Referer: <a href=“http://www.google.cn/”>http://www.google.cn/</a>
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; TheWorld)
Host: <a href=“http://www.google.cn”>www.google.cn</a>
Connection: Keep-Alive
Cookie: PREF=ID=80a06da87be9ae3c:U=f7167333e2c3b714:NW=1:TM=1261551909:LM=1261551917:S=ybYcq2wpfefs4V9g;
NID=31=ojj8d-IygaEtSxLgaJmqSjVhCspkviJrB6omjamNrSm8lZhKy_yMfO2M4QMRKcH1g0iQv9u-2hfBW7bUFwVh7pGaRUb0RnHcJU37y-
FxlRugatx63JLv7CWMD6UB_O_r
其中,HTTP请求是由客户端发出的消息,用于请求服务器执行某个操作,它的起始行包括以下3项:
- HTTP方法:也称HTTP动词,如GET、PUT、POST等,它们描述 要执行的动作
- 请求目标:通常是一个URL,它代表所要访问的资源。
- HTTP版本:通常是HTTP/1.1
而HTTP响应的起始行被称作状态行,包含以下三项。
- 协议版本:通常为HTTP/1.1
- 状态码(Status Code):它表明请求是否成功,常见的状态码是200、404、500等。
- 状态文本(Status ):一个简短的文本信息,用于描述状态码。
HTTP方法
- GET 获取指定的资源,它并不会修改资源,以因此GET方法是安全的。所谓安全方法,是指不会修改资源的方法。此外GET方法也是幂等的。所谓幂等是指多次对同一个URL调用同一个HTTP方法,其效果总是一样的。
- POST 创建资源,POST方法不是安全方法,因为它会修改服务器上的资源,并且也不是幂等方法,多次请求同一个POST操作会产生多个不同的资源
- PUT方法的作用是更新资源,因为PUT会修改资源,所以也不是安全方法,与POST方法不同的是,PUT方法是幂等的,多次更新同一个资源,其返回结果都是一样的。PUT方法除了更新资源外,当资源不存在时,它还可以创建资源``需要注意的是,尽管POST与PUT方法都可以创建资源,但他们请求的URI是有区别的POST请求的URI是资源集合,而PUT则是请求单个不存在的资源,例如:
- DELETE方法的作用是删除资源,它不是安全的,但它是幂等的,这意味着对同一资源请求多次DELETE方法,效果都是一样的。当第一次对资源调用DELETE方法时,返回表示操作成功的200 OK状态码,后续再调用DELETE方法,由于资源已经不存在,则应返回404 NotFound状态码。
- PATCH方法与GET方法相同,但它并不返回消息正文,在响应消息中仅包含响应状态码与消息头,该方法常用来检测资源是否存在以及获取资源的元数据。
- OPTIONS方法用于获取资源支持的操作,服务器在返回的响应中会包含Allow消息头,它的值为HTTP方法列表,例如:
Allow:GET,POST
综上所述,常见的HTTP方法总结下:
方法名称 | 作用 | 安全 | 幂等 |
---|---|---|---|
GET | 获取资源 | Y | Y |
POST | 创建资源 | N | N |
PUT | 更新指定的资源 | N | Y |
DELETE | 删除指定的资源 | N | Y |
PATCH | 对资源进行部分更新 | N | N |
HEAD | 与GET方法作用完全一样,但在响应中没有消息正文 | Y | Y |
OPTION | 获取指定资源所支持的操作 | Y | Y |
HTTP消息头
客户端和服务器之间的请求消息与响应消息中均包含消息头,用来传递附加消息。一个消息头由消息名称和它的值组成,中间用冒号“:”隔开,比如Content-Type:text/plain.
每个消息头都有特定的意义,比如上例的消息头用来指明请求或响应消息中正文的内容类型。HTTP请求与响应均可包含多个消息头。
除了标准的HTTP消息头外,一些Web应用程序还会增加自定义消息头,用于返回一些描述或备注类的消息。自定义的名称一般以“X-”开头,以此指明它并不是一个标准的HTTP消息头,例如 X-AspNet-Version用于指明当前服务器运行的ASP.NET 的版本。
Header | 解释 | 示例 |
---|---|---|
Accept | 指定客户端能够接收的内容类型 | Accept: text/plain, text/html |
Accept-Charset | 浏览器可以接受的字符编码集。 | Accept-Charset: iso-8859-5 |
Accept-Encoding | 指定浏览器可以支持的web服务器返回内容压缩编码类型。 | Accept-Encoding: compress, gzip |
Accept-Language | 浏览器可接受的语言 | Accept-Language: en,zh |
Accept-Ranges | 可以请求网页实体的一个或者多个子范围字段 | Accept-Ranges: bytes |
Authorization | HTTP授权的授权证书 | Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== |
Cache-Control | 指定请求和响应遵循的缓存机制 | Cache-Control: no-cache |
Connection | 表示是否需要持久连接。(HTTP 1.1默认进行持久连接) | Connection: close |
Cookie | HTTP请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器。 | Cookie: $Version=1; Skin=new; |
Content-Length | 请求的内容长度 | Content-Length: 348 |
Content-Type | 请求的与实体对应的MIME信息 | Content-Type: application/x-www-form-urlencoded |
Date | 请求发送的日期和时间 | Date: Tue, 15 Nov 2010 08:12:31 GMT |
Expect | 请求的特定的服务器行为 | Expect: 100-continue |
From | 发出请求的用户的Email | From: user@email.com |
Host | 指定请求的服务器的域名和端口号 | Host: www.zcmhi.com |
If-Match | 只有请求内容与实体相匹配才有效 | If-Match: “737060cd8c284d8af7ad3082f209582d” |
If-Modified-Since | 如果请求的部分在指定时间之后被修改则请求成功,未被修改则返回304代码 | If-Modified-Since: Sat, 29 Oct 2010 19:43:31 GMT |
If-None-Match | 如果内容未改变返回304代码,参数为服务器先前发送的Etag,与服务器回应的Etag比较判断是否改变 | If-None-Match: “737060cd8c284d8af7ad3082f209582d” |
If-Range | 如果实体未改变,服务器发送客户端丢失的部分,否则发送整个实体。参数也为Etag | If-Range: “737060cd8c284d8af7ad3082f209582d” |
If-Unmodified-Since | 只在实体在指定时间之后未被修改才请求成功 | If-Unmodified-Since: Sat, 29 Oct 2010 19:43:31 GMT |
Max-Forwards | 限制信息通过代理和网关传送的时间 | Max-Forwards: 10 |
Pragma | 用来包含实现特定的指令 | Pragma: no-cache |
Proxy-Authorization | 连接到代理的授权证书 | Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== |
Range | 只请求实体的一部分,指定范围 | Range: bytes=500-999 |
Referer | 先前网页的地址,当前请求网页紧随其后,即来路 | Referer: http://www.zcmhi.com/archives/71.html |
TE | 客户端愿意接受的传输编码,并通知服务器接受接受尾加头信息 | TE: trailers,deflate;q=0.5 |
Upgrade | 向服务器指定某种传输协议以便服务器进行转换(如果支持) | Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11 |
User-Agent | User-Agent的内容包含发出请求的用户信息 | User-Agent: Mozilla/5.0 (Linux; X11) |
Via | 通知中间网关或代理服务器地址,通信协议 | Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) |
Warning | 关于消息实体的警告信息 | Warn: 199 Miscellaneous warning |
HTTP Responses Header 响应头
Header | 解释 | 示例 |
---|---|---|
Accept-Ranges | 表明服务器是否支持指定范围请求及哪种类型的分段请求 | Accept-Ranges: bytes |
Age | 从原始服务器到代理缓存形成的估算时间(以秒计,非负) | Age: 12 |
Allow | 对某网络资源的有效的请求行为,不允许则返回405 | Allow: GET, HEAD |
Cache-Control | 告诉所有的缓存机制是否可以缓存及哪种类型 | Cache-Control: no-cache |
Content-Encoding | web服务器支持的返回内容压缩编码类型。 | Content-Encoding: gzip |
Content-Language | 响应体的语言 | Content-Language: en,zh |
Content-Length | 响应体的长度 | Content-Length: 348 |
Content-Location | 请求资源可替代的备用的另一地址 | Content-Location: /index.htm |
Content-MD5 | 返回资源的MD5校验值 | Content-MD5: Q2hlY2sgSW50ZWdyaXR5IQ== |
Content-Range | 在整个返回体中本部分的字节位置 | Content-Range: bytes 21010-47021/47022 |
Content-Type | 返回内容的MIME类型 | Content-Type: text/html; charset=utf-8 |
Date | 原始服务器消息发出的时间 | Date: Tue, 15 Nov 2010 08:12:31 GMT |
ETag | 请求变量的实体标签的当前值 | ETag: “737060cd8c284d8af7ad3082f209582d” |
Expires | 响应过期的日期和时间 | Expires: Thu, 01 Dec 2010 16:00:00 GMT |
Last-Modified | 请求资源的最后修改时间 | Last-Modified: Tue, 15 Nov 2010 12:45:26 GMT |
Location | 用来重定向接收方到非请求URL的位置来完成请求或标识新的资源 | Location: http://www.zcmhi.com/archives/94.html |
Pragma | 包括实现特定的指令,它可应用到响应链上的任何接收方 | Pragma: no-cache |
Proxy-Authenticate | 它指出认证方案和可应用到代理的该URL上的参数 | Proxy-Authenticate: Basic |
refresh | 应用于重定向或一个新的资源被创造,在5秒之后重定向(由网景提出,被大部分浏览器支持) | Refresh: 5; url=http://www.zcmhi.com/archives/94.html |
Retry-After | 如果实体暂时不可取,通知客户端在指定时间之后再次尝试 | Retry-After: 120 |
Server | web服务器软件名称 | Server: Apache/1.3.27 (Unix) (Red-Hat/Linux) |
Set-Cookie | 设置Http Cookie | Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1 |
Trailer | 指出头域在分块传输编码的尾部存在 | Trailer: Max-Forwards |
Transfer-Encoding | 文件传输编码 | Transfer-Encoding:chunked |
Vary | 告诉下游代理是使用缓存响应还是从原始服务器请求 | Vary: * |
Via | 告知代理客户端响应是通过哪里发送的 | Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) |
Warning | 警告实体可能存在的问题 | Warning: 199 Miscellaneous warning |
WWW-Authenticate | 表明客户端请求实体应该使用的授权方案 | WWW-Authenticate: Basic |
状态码
HTTP响应状态码由3个数字组成,用于指明HTTP请求的结果。在状态码后会有一个状态文本,它以文本形式简单描述状态的信息,如200 OK、404 Not Found 和500 Internal Server Error等。更具其表述意义,状态码可分为以下5类:
- 1xx:信息,服务器收到请求,需要请求方继续执行操作。
- 2xx:成功 ,服务器成功执行客户端所请求的操作。
- 3xx:重定向,需要进一步的操作已完成请求。
- 4xx:客户端错误,请求包含语法错误或请求内容不正确
- 5xx:服务端错误,服务器在处理请求的过程中发生了错误。
状态码以其首位数字表示它所属的类别,而后两位则表示在该类型中具体的信息。