http基础
UDP
UDP是面向无连接的网络传输协议。通信都不需要,所以具有不可靠性。由于它的不可靠性,不用保证数据的有序完整,所以它又具有高效性。
TCP三次握手
客户端首先向服务端发送一个带有SYN的请求(第一次握手);服务端收到请求后返回带有SYN/ACK的响应(第二次握手);客户端收到响应后再返回一个带有ACK的数据包给服务端(第三次握手)。
基本概念
HTTP,为超文本传输协议。是互联网应用最为广泛的一种网络协议,所有的 www 文件都必须遵守这个标准。HTTP 可以分为两个部分,即请求和响应。
HTTP 请求:
HTTP 请求由 3 个部分构成,分别是:状态行,请求头(Request Header),请求正文。
实例:
HTTP 响应:
HTTP 响应三个部分构成,分别是:状态行,响应头(Response Header),响应正文。
HTTP头信息
先介绍一下HTTP请求头信息
header | 解释 | 实例 |
---|---|---|
Accept | 指定客户端能够接收的内容类型 | Accept: text/plain, text/html |
Accept-Encoding | 表示浏览器有能力解码的编码类型 | Accept-Encoding: compress, gzip |
Accept-Language | 表示浏览器所支持的语言类型 | Accept-Language: en,zh |
Cache-Control | 指定请求和响应遵循的缓存机制 | Cache-Control: no-cache |
Connection | 是否需要持久连接(HTTP 1.1 默认进行持久连接即为 keep-alive, HTTP 1.0 则默认为 close) | Connection: close |
Cookie | HTTP请求发送时,会把保存在该请求域名下的所有cookie值一起发送给web服务器。 | Cookie: $Version=1; Skin=new; |
Host | 表示请求的服务器网址 | Host: www.zcmhi.com |
User-Agent | 用户代理,简称UA,它是一个特殊字符串头,使得服务器能够识别客户端使用的操作系统及版本、CPU 类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等。 | User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) |
Content-Length | 请求的内容长度 | Content-Length: 348 |
Referer | 先前访问的网页的地址 | Referer: http://www.zcmhi.com/archives/71.html |
Content-Type | 内容的类型,GET 请求无该字段,POST 请求中常见的有 application/x-www-form-urlencoded 为普通的表单提交,还有文件上传为 multipart/form-data | Content-Type: application/x-www-form-urlencoded |
HTTP响应头信息
Connection, Content-Encoding, Content-Type 和请求头的内容差不多,不再赘述。
header | 解释 | 实例 |
---|---|---|
Date | 原始服务器消息发出的时间 | Date: Tue, 15 Nov 2010 08:12:31 GMT |
Last-Modified | 请求资源的最后修改时间 | Last-Modified: Tue, 15 Nov 2010 12:45:26 GMT |
Expires | 响应过期的日期和时间 | Expires: Thu, 01 Dec 2010 16:00:00 GMT |
Set-Cookie | 设置Http Cookie,下次浏览器再次访问的时候会带上这个 Cookie 值 | Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1 |
Server | 服务器软件名称 | Server: Apache/1.3.27 (Unix) (Red-Hat/Linux) |
详细信息请参考: HTTP响应头和请求头信息对照表
HTTP状态码
- 1xx : 表示请求已经接受了,继续处理。
- 2xx : 表示请求已经处理掉了。
- 3xx : 重定向。
- 4xx : 一般表示客户端有错误,请求无法实现。
- 5xx : 一般为服务器端的错误。
常见状态码:
- 200 - 请求成功
- 301 - 资源(网页等)被永久转移到其它URL
- 304 - 通知浏览器复用本地缓存
- 404 - 请求的资源(网页等)不存在
- 500 - 内部服务器错误
Content-Type
Content-Type标头告诉客户端实际返回的内容的内容类型。
- text/html : HTML格式
- text/plain :纯文本格式
- application/json: JSON数据格式
- application/x-www-form-urlencoded :
- multipart/form-data : 需要在表单中进行文件上传时,就需要使用该格式
浏览器缓存
浏览器缓存有四种:
- Memory Cache
- Http Cache
- Service Worker Cache(JS的离线缓存,暂无需了解)
- Push Cache(HTTP2新特性,无需了解)
先说Memory Cache:
MemoryCache,是指存在内存中的缓存。
形如“(from xxx)”的描述,就是我们通过缓存获取到的。“from memory cache”对标到 Memory Cache 类型,“from ServiceWorker”对标到 Service Worker Cache 类型。
下面主要讲解Http Cache:
Http缓存分成强缓存和协商缓存。
强缓存
利用 http 头中的 Expires 和 Cache-Control两个字段来控制的。若命中强缓存,则不会再与服务端发生通信。
命中强缓存的情况下,返回的 HTTP 状态码为 200 (如下图)。from disk cache
强缓存的实现:
-
expires:当服务器返回响应时,会在响应头中携带expires字段;当再次请求该资源时,浏览器会先对比本地时间和 expires 的时间戳,如果小于expires,则直接从缓存中取。但本地时间和服务器时间可能会存在差异,所以一般会使用Cache-Control字段控制。
-
Cache-Control:一般通过Cache-Control的max-age字段来控制资源的有效期,max-age为一个时间长度。
max-age的设置也会存在弊端:只要请求的链接不变,且仍在有效缓存时间内,客户端就无法得知服务器中文件是否更新。所以,需要给打包完成的js文件加上hash,若js内容不变则hash码不变,这样就可以使用静态资源缓存。
Cache-Control常见指令如下:
- max-age -- 有效的缓存时间长度。
- no-cache -- 绕开浏览器,直接服务器验证;如果资源没有过期,直接返回304状态码,告知浏览器复用本地缓存。(走的是协商缓存路线)
- no-store -- 禁止缓存
协商缓存:
主要是两个字段:Last-modified和Etag
-
Last-modified
客户端第一次发起请求后,服务端返回200,响应体会包含Last-Modified的属性标记此文件在服务端最后被修改的时间。当客户端再次发起请求后,客户端把第一次Last-Modified的值存储在If-Modified-Since里面发送给服务端来验证资源有没有修改。如果有修改正常服务端返回资源,状态码200,如果没有修改只返回响应头,状态码304,告知浏览器资源的本地缓存还可用。 -
Etag(类似hash)
资源的唯一标识,用于标识URL对象是否改变。服务端会在客户端第一次请求某一个URL时把这个标识放到响应头传到客户端。当客户端再次发起这个请求时,会把第一次的Etag值存储在If-None-Match里面发送给服务端来验证资源有没有修改。
const http = require('http');
const fs = require('fs');
http.createServer(function (req, res) {
const html = fs.readFileSync('F:/http/lesson5-(last-modified,etag)/test.html', 'utf8')
if (req.url === '/') {
res.writeHead(200, {
'Content-type': 'text/html'
});
res.end(html)
}
if (req.url === '/script.js') {
const etag = req.headers['if-none-match'];
if(etag === '777') {
res.writeHead(304, {
'Content-type': 'text/javascript',
'Cache-Control': 'max-age=2000, no-cache', // no-cache 缓存要经过服务器验证 no-store 禁止缓存
'Last-modified': '123',
'Etag': '777', // etag 用于标示URL对象是否改变,
// 当客户端再次试图访问某个文件,发现缓存过期,客户端会在本次请求的请求头里携带If-Moified-Since和If-None-Match(即之前的Etag值)这两个字段,
// 服务器通过这两个字段来判断资源是否有修改,如果有修改则返回状态码200和新的内容,
// 如果没有修改返回状态码304便知道了本地缓存虽然过期但仍然可以用,于是加载本地缓存。
});
res.end('')
} else {
res.writeHead(200, {
'Content-type': 'text/javascript',
'Cache-Control': 'max-age=2000, no-cache', // no-cache 缓存要经过服务器验证 no-store 禁止缓存
'Last-modified': '123',
'Etag': '777', // etag 用于标示URL对象是否改变,
// 当客户端再次试图访问某个文件,发现缓存过期,客户端会在本次请求的请求头里携带If-Moified-Since(即之前的Last-modified的值)和If-None-Match(即之前的Etag值)这两个字段,
// 服务器通过这两个字段来判断资源是否有修改,如果有修改则返回状态码200和新的内容,
// 如果没有修改返回状态码304便知道了本地缓存虽然过期但仍然可以用,于是加载本地缓存。
});
res.end('console.log("script loaded twice")')
}
}
}).listen(8888);
console.log('server listening on 8888');
浏览器整个缓存策略的过程如下图:
当我们的资源内容不可复用时,直接为 Cache-Control 设置 no-store,拒绝一切形式的缓存;否则考虑是否每次都需要向服务器进行缓存有效确认,如果需要,那么设 Cache-Control 的值为 no-cache;否则考虑该资源是否可以被代理服务器缓存,根据其结果决定是设置为 private 还是 public;然后考虑该资源的过期时间,设置对应的 max-age 和 s-maxage 值;最后,配置协商缓存需要用到的 Etag、Last-Modified 等参数。
Cookie
HTTP Cookie是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。
Cookie主要用于以下三个方面:
- 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
- 个性化设置(如用户自定义设置、主题等)
- 浏览器行为跟踪(如跟踪分析用户行为等)
创建cookie
服务器使用Set-Cookie响应头部向用户代理(一般是浏览器)发送Cookie信息。一个简单的Cookie可能像这样:
Set-Cookie: <cookie名>=<cookie值>
nodejs中设置cookie方法如下:
http.createServer(function (req, res) {
const html = fs.readFileSync('F:/http/lesson6-cookie/test.html', 'utf8')
if (req.url === '/') {
res.writeHead(200, {
'Content-type': 'text/html',
'Set-Cookie': ['id=123; max-age=2', 'abc=456; HttpOnly'] // HttpOnly 那么通过js脚本将无法读取到cookie信息,防止xss攻击
});
res.end(html)
}
}).listen(8888);
为避免跨域脚本 (XSS) 攻击,通过JavaScript的 Document.cookie API无法访问带有 HttpOnly 标记的Cookie。
参考文档: