1、前言

    好久没写博客了,最近虽然没什么假期,但是却比以前还忙!工作、工作、工作,就像赶集似的,聚在一起。对于Web开发人员来说,深入了解HTTP有助于我们开发出更好、更高的Web应用程序。当应用程序出现问题的时候也能够很容易的找出并解决bug。

2、HTTP简介

    超文本传输协议(Hyper Text Transfer Protocol)协议,它是互联网上应用最为广泛的一种网络协议,即基于TCP/IP协议的应用层协议。其中最为常见的逛淘宝京东浏览网页的过程,就是通过HTTP协议来传递浏览器与服务器之间的请求与响应的。

Asp.Net Core 中的HTTP协议详解-LMLPHP

    从图可以看出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类型

     其中常见的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表单内容等),或者响应资源中的描述,这一部分可以为空不是必须的。

Asp.Net Core 中的HTTP协议详解-LMLPHP

    可以看出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。

Asp.Net Core 中的HTTP协议详解-LMLPHP

    一般情况来说我用的最多的就是post、get 我的api接口中基本都是这两个哈哈。常见的HTTP方法总结如下

http方法总结

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);
            }
        }
10-09 12:39