赞
踩
HTTP(Hyper Text Transfer Protocol 超文本传输协议
)协议是基于TCP/IP协议的用于传递数据的协议,其默认端口为80/TCP,简单来说就是客户端与服务器收发收据时遵循的格式,客户端的请求头部文件和服务器的响应头部文件都遵循一定的格式,其总体就是一个大字符串。
HTTP协议是建立在TCP协议的基础上的,要进行HTTP的请求与响应则必须先建立TCP连接,据说存在处于研究阶段的依赖TCP/UDP混合协议的HTTP协议,但当前主流的HTTP协议包括1.0/1.1版本都是依赖于TCP连接的。
HTTP协议的头部文件
与TCP/UDP协议类似的,HTTP也会在数据之上进行封包,其头部文件用于实现诸多功能。
(1)客户端的请求头部文件(request header):
GET / HTTP/1.1 # 表示请求的方法/路径(即/,若有后续则会继续添加)和HTTP协议的版号,请求方法见后文
Host: www.baidu.com # 表示请求服务器的IP地址和端口(网站的服务器会用域名掩盖自己的IP地址,也有CDN和反向代理等情况)
Connection: keep-alive # 表示连接状态
Cache-Control: max-age=0 #指定缓存机制
Content-Length: 557 # 显示长度
Content-Type: application/json; charset=UTF-8 # 标识传输数据格式及编码方法
Upgrade-Insecure-Requests: 1 # 可以指定另外一种可能完全不同的协议
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.75 Safari/537.36 # 表示浏览器的版本
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3 # 浏览器可以接受的格式
Accept-Encoding: gzip, deflate, br # 接收的编码方法,通常是压缩方法
Accept-Language: zh-CN,zh;q=0.9 # 接收的语言
Cookie:xxxx # cookie中的值用于标记一个浏览器,还可以记录访问记录等
注:此中只是一些较常用的请求头,由于HTTP请求一般是浏览器或具有浏览器功能的应用程序发起的,因此对于不同的浏览器和不同功能的请求,其请求头很可能有不同的内容,但大体上都是用于标记与浏览器、连接、传输控制等相关的选项及内容。
(2)服务器的响应头部文件(response header)
HTTP/1.1 200 OK # 表示HTTP协议的版本号和响应状态码及简单描述 Bdpagetype: 1 Bdqid: 0xf1aa3c38000ecaae # 此两者是baidu首页的响应内容,猜测为与服务器相关 Cache-Control: private # 指定缓存机制,对于单个用户的整个或部分响应消息,不能被共享缓存处理,只能用缓存内容回应先前请求该内容的那个用户 Connection: Keep-Alive # 表示连接状态 Content-Encoding: gzip # 返回的压缩格式 Content-Type: text/html; charset=utf-8 # 服务器响应的对象的类型,可指定编码,MIME(Multipurpose Internet Mail Extensions)是描述消息内容类型的因特网标准,如text/html前部分是大类,后部分是具体种类,通常只有在互联网上获得广泛应用的格式才会获得一个 MIME Type,否则只能以application/x-开头 Content-Disposition: attachment/inline; filename='xx.jpg' # 意为弹出下载框/内嵌显示(只针对可内嵌显示的类型,否则依然弹出下载框) Date: Sun, 17 Mar 2019 02:13:18 GMT # 服务器当前时间 Server: BWS/1.1 # 服务器简称 Set-Cookie: xxxx # 标记cookie Strict-Transport-Security: max-age=172800 Vary: Accept-Encoding # WEB服务器指定给Cache服务器,在什么条件下才可以响应后续请求,可以防止Cache服务器响应压缩包给不具解压缩能力的浏览器 X-Ua-Compatible: IE=Edge,chrome=1 Transfer-Encoding: chunked # 服务器表明自己对本响应消息体作了怎样的编码,chunked表示分块。 Expires: Thu, 10 Dec 2015 23:21:37 GMT # 过期时间,在此日期之前客户端认为缓存是 有效的,但客户端和服务器的时间设置可能不同,无法精确控制; Cache-Control: max-age=3600 # 响应后的相对秒数,只支持HTTP1.1,当客户端Expires与此都能解析的时候,会优先使用Cache-Control; Last-Modified: Mon, 30 Nov 2015 23:21:37 GMT # 第一次请求时,服务器返回此响应头标记此文件在服务期端最后被修改的时间; If-Modified-Since: Mon, 30 Nov 2015 23:21:37 GMT # 第二次请求时浏览器发送此请求头询问该资源是否被修改过,若未改变则返回304(Not Changed); ETag: "d41d8cd98f00b204e9800998ecf8427e" # 其定义为“被请求变量的实体值”,在第一次请求时服务器返回此响应头(hash计算实体值); If-None-Match: W/"d41d8cd98f00b204e9800998ecf8427e" # 第二次请求时发送此请求头,若未改变则返回304,若改变则重新请求资源;
注:①与请求头类似的,根据发回响应的服务器的类型和请求的具体内容/功能不同,其响应头也会有很大的区别,要注意在响应头中专门添加了多个选项用于标志缓存相关内容;
②请求头与响应头都是可以自定义的,只要两方对应的浏览器/服务器可以解析(即使不能解析也不影响正常功能,有部分信息就只是用作标志),但对于一些常用的特定功能的请求头,其格式是固定的。
HTTP的请求方法
即客户端向服务器发送HTTP请求时的请求方法,HTTP协议对此有具体的规定,常用的有以下几种:
GET:客户端通常使用这个方法从web服务器请求一个资源,Flask的默认HTTP方法是GET方法。
POST:允许客户端向WEB服务器发送数据。
HEAD:类似于GET请求,但返回的响应中没有具体的内容,用于获取报头。
PUT:从客户端向服务器传送的数据代替指定文档中的内容。
DELETE:请求服务器删除指定的页面。
CONNECT:把服务器当作跳板,让服务器代替访问其他页面。
OPTIONS:允许客户端查看服务器的性能。
TRACE:回显服务器收到的请求,主要用于测试和诊断。
注:服务器可以设定只接收哪几种方法的请求,其中最通用的就是GET/POST方法,其他方法相对不常用,一般只用于一些特殊的功能和页面。
HTTP状态码
是WEB客户端发送请求至WEB服务器后,服务器响应的状态码,每一个请求都会生成状态码。
100~199:信息消息,服务器在提供关于客户端请求的详细信息。 200~299:成功消息,服务器已经接收、理解和处理客户端的请求,一切正常。 300~399:重定向消息,服务器通知客户端请求可以在别处处理。 400~499:客户端错误消息,服务器从客户端接收到一个它不理解也无法处理的请求。 500~599:服务器错误消息,服务器从客户端接收到一个请求,但是服务器尝试处理这个请求时失败了。 200 OK 成功,服务器已处理请求并提供网页 204 No Content 无内容,服务器成功处理了请求,但没有返回任何内容。 206 Partial Content 部分内容,服务器成功处理了部分 GET 请求。 301 永久移动 304 未修改,使用缓存,不会返回网页内容 305 使用代理 401 未授权 403 禁止,服务器拒绝请求 404 未找到 405 方法禁用 410 已删除 500 服务器内部错误 502 错误网关 503 服务不可用 504 网关超时 505 HTTP版本不支持
注:状态码是可以由服务器自主设定的,其可以不遵循上述通用的规定,但一般不这样做。
HTTP的请求流程
HTTP请求和响应都分为两部分,其头部信息都是连续的,在空行后就是body,POST方法中请求头下也会包含请求body。
①浏览器向服务器发送HTTP请求,其中如果是POST方法,则请求头下还会包含body信息;
②服务器向浏览器返回HTTP响应,通常服务器的HTTP响应都会携带内容,即空行后的body,响应的HTML源码就包含在body中;
③浏览器解析服务器的HTTP响应,当浏览器读取到服务器的HTML源码后解析,显示页面,然后,根据HTML里面的各种链接,再发送HTTP请求(这个额外的请求是浏览器解析之后自动发出的)给服务器,拿到相应的图片、视频、Flash、JavaScript脚本、CSS等各种资源,最终显示出一个完整的页面,因此在Network下面能看到很多额外的HTTP请求。
注意在HTTP/1.0中一个HTTP请求只处理一个资源,如果需要其他资源则浏览器会发送另一个HTTP请求,也就是短连接。
HTTP的长连接与短连接
短连接:在HTTP1.0中,客户端的每次请求都要求建立一次单独的连接(包含整个TCP3握4挥的完整流程),处理完请求后马上释放连接
长连接:在HTTP1.1中,默认使用长连接,其标志写在响应头中(Connection:keep-alive),支持在建立一个TCP连接后,发送多个HTTP请求,在所有请求处理完毕或超时后,断开连接;
这个连接不会永久保持,有可能存在一个超时时间,也有可能存在一个最大响应次数,或者使用探测包、客户端每隔一段固定的时间向服务器发送一次“保持连接”的请求等方式来检测当前连接,当客户端在2小时内没有动作,则服务器会探测客户端状态,根据响应来开启保活计时器和探测报文机制,判断是否终止连接。
HTTP长连接与短连接的优缺点和适用情况
①长连接可以省去较多的TCP建立和关闭的操作,减少资源浪费,节约时间,但其探测周期长,且当保持连接的客户端增加时对服务器的压力变大,可以采取关闭长时间没有读写事件的连接、限制每个客户端的最大长连接数等措施,适用于频繁请求资源的客户;
②短链接对于服务器来说管理比较简单,存在的连接都是有用的连接,但如果客户请求频繁,将在TCP连接的建立和关闭操作上浪费时间和资源。
长连接和短连接的产生取决于客户端和服务器的关闭策略。
注:在建立连接消耗很大的情况下如无线通讯,通常每个应用都会维护一个长连接……但IOS系统不同,其由系统维护一个长连接与苹果服务器交互,任何信息都由苹果服务器推送再由系统处理显示在应用中,因此苹果相对安卓省电省资源。
HTTP的无状态及其与TCP/IP协议的关系
HTTP是应用层协议,TCP是传输层协议,IP是网络层协议,HTTP是建立在TCP协议的基础上的,IP协议主要用于解决网络路由和寻址问题(定义数据传输通道),TCP协议主要解决如何在IP层之上保证可靠的传递数据包,保证其连接和顺序正确(定义数据传输和连接方式),HTTP协议主要解决如何包装和识别传输的数据(定义数据传输和内容格式的规范)。
HTTP的无状态:无状态意为对于事务处理没有记忆功能,即每个请求都是独立的,对于服务器来说,同一个客户端的两次请求是没有联系的,HTTP也不关心每一次请求的内容、原因或目的,它只用来完成传输请求和响应这个动作。HTTP的无状态是历史的原因,因为有状态的连接会耗费大量资源,而仅仅是静态页面并不需要有状态的连接,因此为了节省资源和增加效率,HTTP设置为无状态。但随着技术的发展,网络应用需要有状态的连接,通过session/cookie/application等状态机制来实现。
UDP的无状态:UDP传输仅仅在IP上加了端口,不确认可靠传输,也不需要连接。
TCP的有状态:TCP通过其报文首部结构来表明各个包之间的关系,其面向连接即三次握手先确认对方的存在,然后进行建立在可靠连接之上的数据传输。
IP的无状态:它只负责将一个IP包发送到指定的IP地址上去,包与包之间没有联系。
HTTP的keep-alive与TCP的keep alive:前者是要使其底层的TCP连接存在时间长,后者是要检查当前的TCP连接是否还存活。
session/cookie与HTTP长链接的关系:没有必然联系,session/cookie是运作在应用层包含于HTTP报文首部中的信息,其作用为判断浏览器与服务器的联系以确定是否使用已存储的数据和判定登录状态(即判断浏览器的身份,其若是重复访问则如何),而HTTP长链接是运作在传输层的以TCP链接为基础的保持TCP链接传输多个HTTP请求的状态(即建立一次TCP连接发送多个HTTP请求)。
总结来说,即使一个连接是长连接,其不过是HTTP封包的内容进行传输时不需要再重新建立TCP连接而已,HTTP封包本身依旧是无状态的,其仍需要状态机制去确认客户端的身份。
注:在短连接中,每一次数据传输完成之后会主动调用close关闭socket(即每一个HTTP请求都重新发起一个TCP连接),但在长连接中,由于多次请求在一个连接中实现,因此服务器需要定义每次传输数据的长度(在响应头中,加入’Content-Length:d%’,冒号后是字节流长度,一般可以直接使用len()来获取要传输的长度)来告诉客户端此次数据传输完成,可以进行下一个HTTP请求。
web框架简述
由前述的基础知识可知,如果想要通过HTTP协议实现两个主机的互联(包括客户端与服务器的互联),则需要完成的工作有:
①输入要发送的数据,将其编码为bytes;
②添加HTTP请求头,TCP封包,IP封包,以太网封包;
③通过交换机发往网关,通过路由寻址,发送至目标主机;
④在目标主机上以太网解包,IP解包,TCP解包,HTTP解包,读取到数据内容。
网络上的每一个HTTP请求/响应信息传递都是通过此流程进行的,但对于发送方来说,只需要输入要发送的数据和目标主机的IP地址(或域名)就可以完成请求的发送,其余工作由浏览器、操作系统、交换机、路由器(网络供应商)完成,而对于接收方来说,即使操作系统可以完成对IP的解包,但TCP、HTTP的解包和请求的回应却都需要自行处理,这个工作重复性相当高,因此就有人,将编程语言提供的socket接口(内含TCP/UDP等传输协议的解包与封包过程)进一步封装,将HTTP请求头的解析与响应头的发送提出并封装,并提供与数据库交互的接口,最终的成品就是web框架。
注:①web框架与web服务器是两种不同的概念,但联系很紧密,web框架是提供一系列可复用的接口(包括但不限于协议解析、响应合成、连接创建等)以减轻开发人员的负担,web服务器是提供了一个可以访问的IP与端口(一个进程),使网络上的主机可以对其进行访问和建立连接;
②现在的web框架一般侧重点在HTTP协议响应头的配置和与数据库交互,而HTTP/TCP协议的解包与封包、TCP连接的创建一般由web服务器负责(前文中的TCP服务器就可以认为是一个简单的web服务器,虽然其没有对HTTP请求头和响应头的处理);
③但某些web框架是包含一个可用于生产的web服务器的(如tornado),大部分web框架都会提供一个用于测试的web服务器(如flask、Django)。
静态资源与动态资源:静态资源即事先写好的无法改变的资源(一些事先写好的HTML代码、图片等),动态资源即根据请求回复不同的内容(或根据实时情况/用户提交数据,一般需要后端运算或与数据库交互),互联网早期都是静态资源,随着技术和网络/硬件条件的提升,慢慢的出现了动态资源,动态资源由于要进行业务逻辑处理,速度上会慢得多。
注:静态资源与动态资源在最终的传输上都是一致的,其不过是提供资源的方式不一致,所谓的动静分离在本质上即某台服务器专用于处理业务逻辑,另外开辟一台服务器用于提供静态资源,可以提高服务器的性能(某些web服务器对于动态/静态资源的支持也是不同的),也可以使开发变得更有条理。
CGI/SGI/WSGI:参前文,此处简述过程:浏览器发送请求,nginx代理服务器接收请求并分发请求给uWSGI服务器(此处nginx服务器与uWSGI服务器使用uwsgi协议通信),uWSGI服务器解析HTTP请求并将具体内容发送给Django框架(此处uWSGI服务器与Django框架使用WSGI协议通信),Django框架起到的作用是WSGI app。
注:①协议就是规定好的通信方式;
②将请求转发这么多次,原因是:Ⅰ负载均衡和安全考虑;
Ⅱ解耦,若web服务器与app强耦合,则当需要修改app内容时也需要修改web服务器内容,当需求增多时代码量会呈指数级增长,处理追踪异常也很难,因此将其分离,最终的实现方式是:nginx服务器负责接收与分发请求,uWSGI服务器负责HTTP协议的封包(并发送响应)与解包(并发送请求内容与注意事项给Django),web框架只负责运算和数据库交互(即业务逻辑);
③为了实现解耦,在web服务器中的一些选项、路径、方法等都由配置文件传入,web服务器代码无需改动,开发人员只需专注于业务逻辑即可。
WSGI协议的简单内容与工作流程
如图所示。
注:上述即简单的server与app交互的过程,web框架如Django和flask只负责最右端的app部分。
此处对一些较重要的但不是那么有体系的知识点进行介绍,后续了解的其他零碎知识点也会补充在此部分中。
URL的组成
Uniform Resource Locator 统一资源定位符,其组成为
scheme://host[:port][/path][:url-params][/?query][#fragment]
scheme:协议,定义因特网服务的类型,如HTTP, FTP, HTTPS, MMS等,最常用的为http与https;
host:port:主机与端口,其中主机可以是IP也可以是域名,端口默认为80,如果不采用80则需要额外输入端口号;
/path:路径,从域名后的第一个/开始到最后一个/为止是虚拟目录部分,它可以是物理地址,但现在一般是抽象地址,非必须,其后还会有一个文件名;
:url-params:用于指定url特殊参数,不常用;
?query:参数,又称搜索/查询部分,其从?开始到#结束,显示为多个关键字参数形式,中间以&隔开;
#fragment:锚点,以#开头,可以理解为书签,其作用为用户打开界面时滚动到锚点位置,如浏览器自动跳转到上次播放位置。
URL的动态/静态/伪静态
(1)静态即有实际物理地址(文件存在于存储设备上)的文件URL,其打开速度快(对SEO可能有加分),但页面/文件多不好管理;
(2)动态URL即带有参数的URL,这个URL只是一个逻辑地址,文件并不真实存在,其适合中大型网站(易于管理占用存储空间小),但打开速度相对慢,URL结构复杂不利于记忆(对SEO可能有减分);
(3)伪静态URL即通过伪静态规则将动态URL伪装成静态网址,也是逻辑地址非真实存在,其URL简单利于记忆,但设置复杂,需要进行额外的计算会增加服务器的负担,对SEO影响与动态类似,可能影响不大。
QQ的实现方式
(1)QQ的登录方式:主机通过路由/代理等与QQ服务器建立连接(建立连接之前首先要通信,这个与QQ服务器的通信方式可以是UDP/8000也可以是TCP/80),建立好的连接都是TCP连接,QQ使用多服务器协作完成对登录者的状态保持,并通过心跳机制来验证用户是否已经下线;
(2)QQ的通信方式:QQ使用的通信方式为UDP优先,其先尝试UDP打洞(其实就是两台主机通过中间服务器的socket建立连接,具体过程以后了解),若成功则直接使用UDP协议通讯,若不成功则使用TCP通过QQ服务器转发(QQ服务器与两方都建立了TCP连接);
(3)QQ为什么优先使用UDP:历史遗留问题,早期的网络条件不好,且epoll技术还未出现,因此若要维持极高并发的TCP连接代价很大,因此其以UDP协议为基础添加了一系列验证机制(如UDP回应包机制),也就是其所谓的新TCP,UDP无连接速度快,在网络条件不好的情况下比TCP的优势大很多(现在某些网络条件不好的地段仍会使用UDP调试)。
C10K问题
其实就是服务器硬件性能有限与日益增长的高并发需求之间的矛盾,要如何找出优化办法使得有限的资源可以充分的利用,提出的解决方案有两种:①多线程,每一个连接都新建立一个线程(但每一个进程/线程都是会消耗系统资源的,CPU在切换时也会消耗时间,在高并发的情况下并不可取,且可扩展性很差);②使用单进程/线程,但使每个进程/线程都可以同时处理多个连接,即前述的异步非阻塞的IO模型,也就是协程;
epoll方法的提出基本解决了类似的C10K/10M问题,并且现在的CPU核心数增多,在单个服务器上也可以实现多进程+协程。
RESTFul
Representational State Transfer,是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。
但还是应该具体情况具体分析,在工程中要以项目规定为准。
简述如下(引自阮一峰的RESTful API 设计指南):
一、域名: 将api部署在专用域名下: http://api.example.com 或者将api放在主域名下: http://www.example.com/api/ 二、版本: 将API的版本号放在url中。 http://www.example.com/app/1.0/info http://www.example.com/app/1.2/info 三、路径: 路径表示API的具体网址。每个网址代表一种资源。 资源作为网址,网址中不能有动词只能有名词,一般名词要与数据库的表名对应。而且名词要使用复数。 错误示例: http://www.example.com/getGoods http://www.example.com/listOrders 正确示例: #获取单个商品 http://www.example.com/app/goods/1 #获取所有商品 http://www.example.com/app/goods 四、使用标准的HTTP方法: 对于资源的具体操作类型,由HTTP动词表示。 常用的HTTP动词有四个。 GET SELECT :从服务器获取资源。 POST CREATE :在服务器新建资源。 PUT UPDATE :在服务器更新资源。 DELETE DELETE :从服务器删除资源。 示例: #获取指定商品的信息 GET http://www.example.com/goods/ID #新建商品的信息 POST http://www.example.com/goods #更新指定商品的信息 PUT http://www.example.com/goods/ID #删除指定商品的信息 DELETE http://www.example.com/goods/ID 五、过滤信息: 如果资源数据较多,服务器不能将所有数据一次全部返回给客户端。API应该提供参数,过滤返回结果。 实例: #指定返回数据的数量 http://www.example.com/goods?limit=10 #指定返回数据的开始位置 http://www.example.com/goods?offset=10 #指定第几页,以及每页数据的数量 http://www.example.com/goods?page=2&per_page=20 六、状态码: 服务器向用户返回的状态码和提示信息,常用的有: 200 OK :服务器成功返回用户请求的数据 201 CREATED :用户新建或修改数据成功。 202 Accepted:表示请求已进入后台排队。 400 INVALID REQUEST :用户发出的请求有错误。 401 Unauthorized :用户没有权限。 403 Forbidden :访问被禁止。 404 NOT FOUND :请求针对的是不存在的记录。 406 Not Acceptable :用户请求的的格式不正确。 500 INTERNAL SERVER ERROR :服务器发生错误。 七、错误信息: 一般来说,服务器返回的错误信息,以键值对的形式返回。 { error:'Invalid API KEY' } 八、响应结果: 针对不同结果,服务器向客户端返回的结果应符合以下规范。 #返回商品列表 GET http://www.example.com/goods #返回单个商品 GET http://www.example.com/goods/cup #返回新生成的商品 POST http://www.example.com/goods #返回一个空文档 DELETE http://www.example.com/goods 九、使用链接关联相关的资源: 在返回响应结果时提供链接其他API的方法,使客户端很方便的获取相关联的信息。 十、其他: 服务器返回的数据格式,应该尽量使用JSON,避免使用XML。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。