Net Core 中的HTTP协议详解
1、前言
好久没写博客了,最近虽然没什么假期,但是却比以前还忙!工作、工作、工作,就像赶集似的,聚在一起。对于Web开发人员来说,深入了解HTTP有助于我们开发出更好、更高的Web应用程序。当应用程序出现问题的时候也能够很容易的找出并解决bug。
2、HTTP简介
超文本传输协议(Hyper Text Transfer Protocol)协议,它是互联网上应用最为广泛的一种网络协议,即基于TCP/IP协议的应用层协议。其中最为常见的逛淘宝京东浏览网页的过程,就是通过HTTP协议来传递浏览器与服务器之间的请求与响应的。
从图可以看出HTTP协议采用了请求/响应模型。当客户端(通常是浏览器)发起HTTP请求,它首先会建立到HTTP服务器指定端口(默认使用80端口)的TCP连接,而HTTP服务器则负责在该端口监听来自客户端的请求。当TCP连接成功后浏览器会向HTTP服务器发送请求命令,如GET/api/SysBanner/BannerDetailsById。一旦收到请求,服务器会根据请求向客户端返回响应。响应内容通常有状态(200 OK)以及很多消息头和消息正文。正文就是资源呀、请求的文件呀、错误信息和其他信息等等。
HTTP协议采用的是明文的协议,大湿兄就说了这种方式不安全,于是乎HTTPS它来了,HTTPS是啥呢,它是超文本传输安全协议(Hypertext Transfer Protocol Secure)也被称之为HTTP over TLS,HTTP over SSL 反正我是记不清。后面有机会再聊聊HTTPS。
3、统一资源定位符
这个是啥呢?所谓统一资源定位符(Unifrom Resource Locator),就是URL说白了就是地址栏那个东东。代表网络上一个特定的资源,用于标识并定位资源。
对于HTTP来讲,当用户在浏览器中书入了一个URL后,意味着他想要获取或查看一些资源种子,像图片、HTML页面、小电影、音乐、可执行文件、office文档等等。要看妹子的图片比如这个http://www.xxx.com/image/xxx.png。对于一个URL 如http://www.xxx.com/image/xxx.png它由以下部分组成。
a、http://,这个是URL协议,它指定了如何访问一个特定的资源,如上栗中的http://会告诉浏览器使用http协议(文本传输协议),当然除了http://协议外还有https://(加密的http协议)、ftp://(文件传输协议)、mailto:(电子邮件协议)等;
b、www.xxx.com,这是主机名,主机会告诉浏览器要访问资源所在的服务器名称。DNS(Domain Name System)会将这个名称解析魏具体的IP地址,通过IP再去访问服务器;
c、这是URL的路径(Path),他指向的就是服务器具体的资源,这一部分变化跟很大,有可能是文件如上栗的www.xxx.com/image/xxx.png 也可以是动态、静态网页www.xxx.com/home/index。当访问网页的时候还包括图片、JS文件、CSS以及其他的资源;
d、端口号,在主机后面以英文冒号 : 隔开。一般来说都省略了只要是默认的80端口,服务器在这个端口上监听HTTP请求。通常在Web调试中才会用到端口号 如http://www.xxx.com:8080;
e、查询字符串,这个就是参数部分。http://www.xxx.com/home/index?a=1&b=2 这里的ab就是查询的参数,如通过身份证查询个人信息通常get请求,多个参数用&分开。这些查询字符串都会发送给HTTP服务器;
f、锚部分、片段(Fagment),就是在#后面的部分,它用于指定资源特定的位置。这与上面的不通,它不会由服务器处理,只会由浏览器定位到不用的位置,常见的VUE就是这种的 http://www.xxx.com/#/home。
由此可见一个完整的URL的格式如下
<protocol>://<host> [ : port ] / [ path ] [ ? query ] [ #fagment ]
4、媒体类型
当HTTP服务器对请求返回响应的时候,它不仅返回资源本身还会在响应中指定资源的内容类型(Content Type),这就是媒体类型。要定制内容类型HTTP依赖于MIME(Multipurpose Internet Mail Extensions)标准,是一种表示文档的性质和格式的标准。MIME它最先用在电子邮件门后面HTTP协议也使用这一标准。浏览器通过MIME类型来决定如何处理文档。图片就显示。对于音频、视频文件只有设置了正确的MIME类型才能被HTML语言中的<video>或者<audio>识别和播放。
当客户端请求HTML页面的时候HTTP服务器会返回HTML内容,并且标识气内容类型为text/html,前面的额text为主类型,后面的html是子类型。当请求一个图片通常内容类型是image/gpeg或者image/gif。座椅MIME的类型合适很简单type/subtype ,由主类型/子类型两个字符串组成,中间用“ / ” 号隔开,不允许空格哦。大小写不敏感,传统习惯性的都是小写。常见的MIME类型如下
常见的MIME类型
类型 | 描述 | 示例 |
text | 普通文本 | text/plain、text/html、text/css、text/javascript |
image | 图片 | image/gif、image/jpeg、image/png、image/bmp、image/webp |
audio | 音频 | audio/midi、audio/webm、audio/ogg、audio/wav |
video | 视频 | video/webm、video/ogg |
application | 二进制数据等 | application/octet-stream、application/vnd.mspowerpoint、application/xml、application/pdf、application/json |
其中常见的MIME类型及其意义如下:
a、text/plain:内容就是纯文本,浏览器认为可以直接显示;
b、text/html:内容为html,即超文本标记语言,所有的HTML内容都是这样的类型;
c、image/jpeg、image/png:这就是jpeg、png图片;
d、application/json:表示json格式的数据,通常api现在接口大部分都是这个。
5、HTTP消息
如果说客户端发出的请求有问题或者服务器上没有请求的资源服务器崩了呀,那么就无法返回客户端想要的结果。这个请求跟响应的过程中就像“对话”一样。双方(客户端服务器)都要理解对方的“语言”这就是HTTP消息要解决的问题啦。当客户端发送请求到服务器的时候,应该是用HTTP协议规定的格式的消息;服务器也会返回规定格式的响应。
HTTP请求消息跟响应消息都有相思的结构,如下。
a、起始行:就是第一行,用于描述请求或者是对应的状态。成功与失败了嘛,这个起始行总是单行哦;
b、HTTP消息头:描述了请求的或者响应的相关属性、哦诶之、对正文消息的描述等;
c、空行:说明消息头已经发送完毕;
d、消息正文:包含请求数据(创立的资源、HTML表单内容等),或者响应资源中的描述,这一部分可以为空不是必须的。
可以看出HTTP请求起始行包含以下内容
a、HTTP方法:如GET、POST、PUT等等描述要执行的动作 ;
b、请求目标:通常是一个URL,表示要访问的资源;
c、HTTP版本:通常是HTTP/1.1。
HTTP响应起始行作为状态行包括以下内容。
a、协议版本:通常HTTP/1.1;
b、状态码(Status Code):表示请求是否成功,常见的200(OK)、404(资源不存在)、500(服务器错误)等等;
c、状态文本(Status Text):一个简短的文本信息,用于描述状态码。
6、HTTP方法
HTTP定义了一组的请求方法来表示对指定资源执行的操作,每个请求都有一个HTTP请求方法,常见的有get、post、put、delete、patch、head、options等。
a、get:作用是用来获取指定资源,它不会修改资源,所以他是安全的。它也是幂等的,所谓幂等就是多次对同一个URL调用同一个HTTP方法,其效果都是一样的(你见过获取产品列表会修改到数据库吗?);
b、post:它是用来创建资源的,因此他修改了服务器的资源了(通常都是数据库多一点)所以不是安全的,并且也不是幂等的;
c、put:它是更新资源的,也是修改了资源也不是安全的。但是它是幂等的,每次更新同一个资源返回的结果都是一样的。跟post不一样的是档资源不存在的时候他还会创建资源;
d、delete:删除资源也是不安全的,幂等的,如果资源不存在会返回404(NOt Found)状态码;
e:patch:更新局部资源,跟put不一样的是它只会更新局部的字段数形二put是全部更新;
f、head:它跟get差不多,但是它不返回消息正文,只有消息头跟状态码,head主要该是用来检测资源是否存在以及获取资源的元数据;
g、options:获取资源支持的操作,服务器返回响应中包含Allow消息头 如Allow:post , get。
一般情况来说我用的最多的就是post、get 我的api接口中基本都是这两个哈哈。常见的HTTP方法总结如下
http方法总结
名 称 | 作 用 | 安 全 | 幂 等 |
GET | 获取资源 | 是 | 是 |
POST | 创建资源 | 否 | 否 |
PUT | 更新制定资源 | 否 | 是 |
DELETE | 删除制定资源 | 否 | 是 |
PATCH | 根据局部资源 | 否 | 否 |
HEAD | 与GET一样但是没有消息正文 | 是 | 是 |
OPTIONS | 获取资源支持的操作 | 是 | 是 |
7、HTTP消息头
无论是请求跟响应中都有消息头,用来传递附加信息。一个消息头由名称跟值组成中间用 : 冒号隔开,如Content-Type:text/plain。HTTP请求与响应中均包含可以多个消息头。如下微信请求的封装类添加的请求消息头。
/// <summary> /// 微信请求Post /// </summary> /// <param name="url">地址</param> /// <param name="requestString">参数</param> /// <param name="merchantIdPwd">商户号密码</param> /// <param name="merchantId">商户号</param> /// <param name="cardPath">证书路径</param> /// <param name="serialNo">商户证书号</param> /// <returns></returns> public async Task<string> WeChatPostAsync(string url, string requestString, string merchantIdPwd, string merchantId, string cardPath, string serialNo) { try { var client = _httpClientFactory.CreateClient(); var requestContent = new StringContent(requestString); requestContent.Headers.ContentType.MediaType = "application/json"; var auth = BuildAuthAsync(url, requestString, merchantIdPwd, merchantId, serialNo, cardPath, "POST"); string value = $"WECHATPAY2-SHA256-RSA2048 {auth}"; client.DefaultRequestHeaders.Add("Authorization", value); client.DefaultRequestHeaders.Add("Accept", "application/json"); client.DefaultRequestHeaders.Add("User-Agent", "WOW64"); client.Timeout = TimeSpan.FromSeconds(60); var response = await client.PostAsync(url, requestContent); if (response.IsSuccessStatusCode) { var result = await response.Content.ReadAsStringAsync(); return result; } else { return $"接口【{url}】请求错误,错误代码{response.StatusCode},错误原因{response.ReasonPhrase}具体的话========================================\n{JsonConvert.SerializeObject(response)}"; } } catch (Exception ex) { SaveLog($"接口【{DateTime.Now + url}】请求错误,错误代码{ex.Message}具体=============================================/n{ex.StackTrace}"); throw new Exception(ex.Message + ex.StackTrace); } }
常见的请求消息头
消息头 | 说 明 | 示 例 |
Accept | 可接受的响应内容类型(Content-Type) | Accept:application/json |
Acceept-Charset | 可接受的字符集 | Acceept-Charset:utf-8 |
Accept-Encoding | 可接受响应内容编码方式 |
Content-Encoding:gzip
|
Accept-Language | 可接受响应内容语言列表 | Accept-Language:en-US |
Authorization | 用于HTTP协议中需要认证资源的认真信息 | Authorization:basic JWT字符 |
Cache-Control | 用来指定丁前请求中是否使用缓存 | Cache-Control:no-cache |
Connection | 客户端(浏览器)想要优先使用的连接方式 | Connection:keep-alive |
Cookie | 向服务器提供Cookie | Cookie:name=value;name2=value2 |
Content-Length | 请求正文的长度 | Content-Length:2048 |
Content-Type | 请求正文中的MIME类型(POST或者PUT请求中) | Content-Type:application/json |
Date | 发送该消息的日期和时间 |
Date:Fri, 08 Oct 2021 14:50:00 GMT
|
Host | 服务器的主机以及使用的端口号 | HOST:www.xx.com |
If-Match | 当客户端的值与服务器上面的对应起来才进行相关操作 | If-Match:ADGJMPDW |
If-Modified-Since | 允许资源被修改是返回304NOt Modified状态码 | If-Modified-Since:Fri, 08 Oct 2021 14:50:00 GMT |
If-None-Match | 当服务器任何资源和服务端提供的值不匹配,服务器才会返回资源 | If-None-Match:ADGJMPDW |
If-Unmodified-Since | 仅当资源某个特定时间以来没有修改的时候才发送响应 | If-Unmodified-Since:Dec,26 Dec 2021 23:4533 GMT |
Orgin | 用于发起一个跨域请求 | Orgin:http://www.xxx.com |
Proxy-Authorization | 用于向代理进行认证的认证信息 | Proxy-Authorization: base jwt字符串 |
User-Agent | 浏览器身份标识符 |
User-Agent:Mozilla/5.0...
|
常见的响应消息头
消息头 | 说 明 | 示 例 |
Allow | 指明资源支持的有效操作 | Allow:GET,POST |
Cache-Control | 指明该响应使用缓存机制 | Cache-Control:max-age=3600 |
Connection | 针对该连接做预期的选项 | Connection:close |
Content-Encoing | 响应正文使用的编码类型 | Content-Encoing:gzip |
Content-Language | 响应正文使用的语言类型 | Content-Language:zh-cn |
Content-Length | 响应正文的长度 | Content-Length:1024 |
Content-Type | 响应正文的MIME类型 | Content-Type:text/html;chartset=utf-8 |
Date | 消息被发送时的日期和时间 | Date:Fri, 08 Oct 2021 14:50:00 GMT |
ETag | 资源当前状态的一个标识符 | ETag:"gikif8f8f68f6ftyjy" |
Expires | 指定一个时间,默认过了这个时间认为响应已经过期 | Expires:Date:Fri, 08 Oct 2021 14:50:00 GMT |
Last-Modified | 请求资源最后修改的日期 | Last-Modified:Date:Fri, 08 Oct 2021 14:50:00 GMT |
Location | 指向另一个URL用于进行重定向,成功创建资源是使用 | Location:https://www.xxx.com/api/auther/1234 |
Proxy-Authenticate | 要求访问代理是提供身份认证信息 | Proxy-Authenticate:basic |
Server | 服务器名称 |
Server:Kestrel 或者 Server:nginx/1.18.0或者Server:Microsoft-IIS/10.0
|
Set-Cookie | 设置HTTP Cookie | Set-Cookie:UId=123,Age=18;Version:1.0 |
WWW-Authenticate | 表示请求应使用的认证方式 | WWW-Authenticate:Basic |
8、HTTP状态码
HTTP的响应状态码由3个数字组成,表示请求的结果,状态码后面有文本简单说明状态的信息。如200 OK、404 Not Found、500 Internet Server Error等等。状态码可以分为一下5类。
a、1xx:信息,服务器收到请求啦,需要对面继续执行操作;
b、2xx:成功,服务器成功执行客户端所请求的操作;
c、3xx:重定向,需要进一步的操作完成(通常我遇到的都是304);
d、4xx:客户端错误,需要检查代码或者请求内容不正确;
e、5xx:服务端错误,服务器在处理请求过程中出现了错误 通常500 最常见。
常见的HTTP状态码
状态码 | 状态码名称 | 描 述 |
200 | OK | 请求操作执行成功,并且返回包含预期的资源 |
201 | Created | 资源创建成功,响应正文为空 |
202 | Accepted | 已接收请求,开始执行异步,但是处理还没有完场 |
204 | No Content | 请求资源成功,响应正文为空 |
301 | Moved Permanently | 请求的资源被永久移动,响应消息中应包含新的资源URL,浏览器会自动重定向到新的URL |
303 | See Other | 对当前请求的响应可以再另一个URL上被找到,该URL在当前响应的Location消息头中 |
304 | Not Modified | 所请求的资源未修改,客户端可以从缓存中得到资源,服务端返回该状态码事,消息正文不包含任何内容(与204 NOt Content 一样) |
307 | Temporary Redirect | 服务端不处理客户端的请求,客户端应向另一个URL请求,该URL在当前响应的Location消息头中 |
400 | Bad Request | 客户端请求存在错误,代码错误,服务端无法理解 |
401 | Unauthorized | 当前请求要访问受保护的资源,没有像服务端提供正确的认证信息或者就没有提供任何认证信息 |
403 | Forbidden | 当请求受保护的资源时,尽管提供了正确的认证信息,但是权限不够禁止访问该资源 |
404 | Not Found | 请求资源不存在 |
405 | Method Not Allowed | 请求的资源不支持客户端指定的的HTTP方法,该响应头中必须包含Allow项,用于表示当前资源能够接收的请求方法列表 |
406 | Not Acceptable | 服务器不支持请求中指定的资源表述格式(Accept消息头指定,请求json你用image/png怎么可能) |
409 | Confict | 请求资源冲突,请求无法完成农,通常是put请求处理冲突 |
412 | Precondition Failed | 客户端请求头重指定了一个或者多个先决条件,服务器无法验证这些先决条件失败 |
415 | Unsupperted Media Type | 请求中使用了服务器不支持的资源表述格式(由Content-Type决定) |
500 | Internet Server Error | 服务器内部错误,无法处理请求(服务器崩了,宕机) |
503 | Service Unavailable | 由于临时的服务器维护或者请求过载,服务器当前无法处理请求 |
知识很宝贵,就好像是金矿。学好知识,掌握好本领,会对我终身有益。请把努力当成一种习惯,而不是三分钟热度。每一个你羡慕的收获,都是努力用心拼来的。