1、GET和POST

GET方法是安全方法,安全是指因为GET方法只是执行获取资源的动作,而POST方法被用于请求服务器接受请求中的实体,作为请求资源的一个新的从属物,所以可能会执行不安全动作。
GET方法有幂等性,幂等的意思是相同的请求请求结果一样,所以GET是幂等性
如果请求消息包含If-Modified-Since,If-Unmodified-Since,If-Match,If-None-Match或者 If-Range头域, GET的语义将
变成“条件(conditionall) GET”。一个条件GET方法会请求满足条件头域的实体。条件 GET 方法的目的是为了减少不必要的网络使用,
这通过允许利用缓存里仍然保鲜的实体而不用多次请求或传输客户端已经拥有的实体来实现的。
POST里的响应是不可缓存的。

2、HTTP状态码

  • 1** 信息,服务器收到请求,需要请求者继续执行操作
  • 2** 成功,操作被成功接收并处理
  • 3** 重定向,需要进一步的操作以完成请求
  • 4** 客户端错误,请求包含语法错误或无法完成请求
    403、405
  • 5** 服务器错误,服务器在处理请求的过程中发生了错误
  1. 100(Continue)
    HTTP1.1中新加入100响应码,目的在于允许客户端判定服务器是否愿意接受客户端发来的消息主体(基于请求头,Expect:
    100-continue),如果服务端愿意接受,返回100(Continue),不愿意接受返回417(Expectation Failed),表示客户端错误,意味着服务器无法满足 Expect 请求消息头中的期望条件。

  2. 2XX
    200 OK 请求成功。请求所希望的响应头或数据体将随此响应返回
    204 No Content 无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档
    206(Partial Content) 部分内容。服务器成功处理了部分GET请求

  3. 3XX
    下面主要介绍3开头的和重定向有关的状态码。客户端发送请求,服务端返回一个3开头的状态码,那么客户端会请求服务端返回的新URL。
    有很多重定向,可以分为三类:
    永久重定向、暂时重定向和特殊重定向。
    永久重定向的是301和308,暂时重定向是302、303和307,特殊重定向是300和304。

  • 301(Moved Permanently)
    永久移动。
    请求资源被赋予一个新的永久URI,并且任何将来对此资源的引用都会利用这个新的URI。
    如果客户端接收了一个来自非GET或HEAD请求方法的301响应, 那么就不能自动的向新URI发送重复请求,除非得到用户的确认。
    使用场景:想换个域名,旧的域名不用啦,这样用户访问旧域名时用301就重定向到新的域名。
  • 308(Permanent Redirect)
  • 302(Found)
    临时移动。
    请求的资源暂时地存放在一个不同的URI下。
    如果客户端发出非GET请求后,收到服务端的302状态码,那么就不能自动的向新URI发送重复请求,除非得到用户的确认。
    但是,很多浏览器都把302当作303处理了,它们获取到HTTP响应报文头部的Location字段信息,并发起一个GET请求。
    使用场景:有时系统进行升级,需要临时更换地址。
  • 303(See Other)
    见其他。
    请求的响应被放在一个不同的URI下,并且应该用GET方法获得那个资源。
    如果客户端发出POST或PUT请求后,收到服务端的303状态码,那么浏览器获取到HTTP响应报文头部的Location字段信息,并发起一个GET请求。
    使用场景:防止POST或PUT请求的二次触发
  • 307(Temporary Redirect)
    临时重定向。
    如果客户端发出非GET请求,那么规范要求其他的请求方法必须等客户确认才能跳转。
    请求方法和请求体都不会改变。
    307 状态码被创建用来消除在使用非 GET 方法时的歧义行为。
  • 300(Multiple Choice)
    多项选择。
    是一种手工重定向:响应的消息主体中包含了一个可能的重定向链接的列表,用户可以从中进行选择。
  • 304(Not Modified)‘
    没有修改。
    表示缓存值依然有效。
  1. 4XX
    400 Bad Request 客户端请求的语法错误,服务器无法理解
    401 Unauthorized 请求要求用户的身份认证
    403 Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求
    404 Not Found 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置”您所请求的资源无法找到”的个性页面
    405 Method Not Allowed 客户端请求中的方法被禁止

  2. 5XX
    500 Internal Server Error 服务器内部错误,无法完成请求
    501 Not Implemented 服务器不支持请求的功能,无法完成请求
    502 Bad Gateway 充当网关或代理的服务器,从远端服务器接收到了一个无效的请求
    503 Service Unavailable 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中
    504 Gateway Time-out 充当网关或代理的服务器,未及时从远端服务器获取请求
    505 HTTP Version not supported 服务器不支持请求的HTTP协议的版本,无法完成处理

3、HTTP请求报文

HTTP请求报文包括:起始行、请求头和请求体。
前端向后台传输的数据有几种类型:表单、字符串、json
Content-type是属于内容头部,通过Content-Type来告诉后台当前请求数据的类型,常见的媒体格式类型如下:
text/html : HTML格式
text/plain :纯文本格式
text/xml : XML格式
image/gif :gif图片格式
image/jpeg :jpg图片格式
image/png:png图片格式
通过Content-Type来告诉后台前端传输的数据类型,常见的类型如下:
application/json :传递的是一个json对象。
application/x-www-form-urlencoded :发送表单
multipart/form-data :需要在表单中进行文件上传时,就需要使用该格式。
HTTP请求头字段:cookie、connection、Content-Type、Host、If-Match、If-Modified-Since、If-None-Match
| Header | 解释 | 示例 |
| :—-: | :—–: | :—-: |
| Accept | 指定客户端能够接收的内容类型 | Accept: text/plain, text/html,application/json |
| 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 |
| Cache-Control | 指定请求和响应遵循的缓存机制 | Cache-Control: no-cache |
| Upgrade | 向服务器指定某种传输协议以便服务器进行转换(如果支持) | Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11 |

3.1 HTTP连接持久化、Content-Length、Transfer-Encoding和Content-Encoding

http1.1中默认开启连接持久化,然而对于连接持久化,我们如何界定请求或响应实体的边界呢?当浏览器不知道这一点,它无法得知这个打开的连接上是否还会有新数据进来,只能傻傻地等了。
这个时候可以通过设置Content-Length。浏览器可以通过 Content-Length 的长度信息,判断出响应实体已结束。那如果 Content-Length 和实体实际长度不一致会怎样?有兴趣的同学可以自己试试,通常如果 Content-Length 比实际长度短,会造成内容被截断;如果比实体内容长,会造成 pending。然而在实际应用中,有些时候实体长度并没那么好获得。
那么Transfer-Encoding 正是用来解决上面这个问题的,在最新的 HTTP 规范里,只定义了一种传输编码:分块编码(chunked)。分块编码相当简单,在头部加入 Transfer-Encoding: chunked 之后,就代表这个报文采用了分块编码。这时,报文中的实体需要改为用一系列分块来传输。每个分块包含十六进制的长度值和数据,长度值独占一行,长度不包括它结尾的 CRLF(\r\n),也不包括分块数据结尾的 CRLF。最后一个分块长度值必须为 0,对应的分块数据没有内容,表示实体结束。按照这个格式改造下之前的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
require('net').createServer(function(sock) {
sock.on('data', function(data) {
sock.write('HTTP/1.1 200 OK\r\n');
sock.write('Transfer-Encoding: chunked\r\n');
sock.write('\r\n');

sock.write('b\r\n');
sock.write('01234567890\r\n');

sock.write('5\r\n');
sock.write('12345\r\n');

sock.write('0\r\n');
sock.write('\r\n');
});
}).listen(9090, '127.0.0.1');

上面这个例子中,我在响应头中表明接下来的实体会采用分块编码,然后输出了 11 字节的分块,接着又输出了 5 字节的分块,最后用一个 0 长度的分块表明数据已经传完了。用浏览器访问这个服务,可以得到正确结果。可以看到,通过这种简单的分块策略,很好的解决了前面提出的问题。
Content-Encoding 通常用于对实体内容进行压缩编码,目的是优化传输,例如用 gzip 压缩文本文件,能大幅减小体积。 Content-Encoding 和 Transfer-Encoding 二者经常会结合来用,其实就是针对进行了内容编码(压缩)的内容再进行传输编码(分块)。

4、HTTP版本

4.1 HTTP1.1相比HTTP1.0

  1. 请求方法
    HTTP1.0中只有三个请求方法:GET、POST、HEAD
    HTTP1.1中增加了PUT、DELETE、OPTIONS、TRACE、CONNECT

  2. 连接持久化
    HTTP 1.1支持连接持久化(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启Connection: keep-alive,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。

  3. 新增100响应码
    HTTP1.1中新加入100响应码,目的在于允许客户端判定服务器是否愿意接受客户端发来的消息主体(基于请求头,Expect: 100-continue),如果服务端愿意接受,返回100(Continue),不愿意接受返回417(Expectation Failed),表示客户端错误,意味着服务器无法满足 Expect 请求消息头中的期望条件。

  4. 新添Host头
    HTTP1.1中添加Host头处理,在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)。

  5. 缓存
    HTTP1.0中的缓存使用Pragma和Expires来规范,Pragma通过no-cache来禁用缓存,Expires来规定缓存的过期时间。
    HTTP1.1中使用cache-control来规定缓存的过期时间,或是禁用缓存,如果缓存过期,则进入第二步与服务端进行再验证使用if-modified-since、if-none-match来进行再验证。

4.2 HTTP2.0相比HTTP1.1

  1. 请求数量
    HTTP1.1协议中浏览器客户端在同一时间,针对同一域名下的请求有一定数量限制。
    而HTTP2中多路复用的特性允许同时通过单一的 HTTP/2 连接发起多重的请求-响应消息。能实现多路复用是因为新增二进制分帧层,消息分帧后可以乱序发送,然后再根据每个帧头部的流标识符重新组装

  2. 请求头压缩
    在HTTP1.x中,头部元数据都是以纯文本的形式发送的,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自
    cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。

  3. 服务器推送
    服务器推送(server push)指的是,还没有收到浏览器的请求,服务器就把各种资源推送给浏览器。
    比如,浏览器只请求了index.html,但是服务器把index.html、style.css、example.png全部发送给浏览器。这样的话,只需要一
    轮 HTTP 通信,浏览器就得到了全部资源,提高了性能。