基本概念
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 : 需要在表单中进行文件上传时,就需要使用该格式
浏览器缓存
浏览器整个缓存策略的过程如下图:
HTTP中与缓存相关的字段
Cache-Control, Last-modified, Etag
Cache-Control
通过cache-control的指令可以告诉客户端或是服务器如何处理缓存。常见的请求指令如下:
- no-cache -- 缓存要经过服务器验证;如果资源没有过期,直接返回304状态码,告知浏览器复用本地缓存。
- no-store -- 禁止缓存
- max-age -- 有效的缓存时间。max-age的设置会造成只要请求的链接不变且仍在有效缓存时间内,当服务端更新文件后客户端并不知道文件已经更新。所以我们通常会给打包完成的js文件加上一段hash码,若js内容不变则hash码不变,这样就可以使用静态资源缓存。
Last-modified
客户端第一次发起请求后,服务端返回200,响应体会包含Last-Modified的属性标记此文件在服务端最后被修改的时间。当客户端再次发起请求后,客户端把第一次Last-Modified的值存储在If-Modified-Since里面发送给服务端来验证资源有没有修改。如果有修改正常服务端返回资源,状态码200,如果没有修改只返回响应头,状态码304,告知浏览器资源的本地缓存还可用。
Etag
资源的唯一标识,用于标识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');
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。
参考文档: