web开发中,必需要了解的HTTP相关知识

本文已同步到github, web开发中,必需要了解的HTTP相关知识,欢迎收藏,欢迎star。javascript

本文主要记录与HTTP相关的具体概念和知识,关于HTTP协议的诞生和历史发展,很少作介绍,可是既然是写HTTP,顺带说两句,上下文也能衔接的上。html

CERN(欧洲核子研究组织)的蒂姆 • 伯纳斯 - 李(Tim Berners - Lee)博士提出了一种能让远隔两地的研究者们共享知识的设想,因而HTTP慢慢的诞生了。java

另外,HTTP协议是无状态协议,因而为了保存用户的状态,cookie诞生了。node

HTTP协议是创建在TCP链接之上的,当浏览器输入URL进行访问,浏览器冲URL中解析出主机名和端口,浏览器创建一条与web服务器的链接,而后才进行http请求。git

TCP链接的创建与终止

创建TCP链接(三次握手)

在客户端与服务端进行http通讯以前,须要创建TCP链接,这时须要三次握手github

(1) 请求新的TCP链接,客户端发送一个小的TCP分组,这个分组设置一个特殊的SYN标记,代表是一个客户端请求。web

(2) 若是服务器接受这个链接,就会对一些链接参数进行计算,并向客户端回送一个TCP分组,发送SY和ACK标记,代表链接请求已经被接受跨域

(3) 最后,客户端向服务器回送一条确认消息,通知服务器链接已经创建。浏览器

HTTP-三次握手

断开TCP链接(四次断开)

创建一个链接须要三次握手,而终止一个链接要通过4次握手。这由TCP的半关闭(half-close)形成的。既然一个TCP链接是全双工(即数据在两个方向上能同时传递),所以每一个方
向必须单独地进行关闭。这原则就是当一方完成它的数据发送任务后就能发送一个FIN来终止
这个方向链接。当一端收到一个FIN,它必须通知应用层另外一端几经终止了那个方向的数据传
送。发送FIN一般是应用层进行关闭的结果。

(1) 客户端发送FIN标记到服务器,代表客户端发起关闭链接缓存

(2) 服务器接收客户端的FIN标记并,向客户端发送FIN的ACK确认标记

(3) 服务器发送FIN到客户端,服务器关闭链接

(4) 服务器端发送一个FIN的ACK确认标记,确认链接关闭

HTTP-四次分手

创建持久链接的请求和响应交互:

HTTP-持久链接的请求和响应交互

使用wireshark进行数据抓包:

这里向你们推荐一款抓包软件Wireshark,能够用来分析TCP链接的创建和断开过程,以及抓取HTTP请求和相应的信息等,下面是我进行一次客户端和服务端通讯的抓包数据截图:

HTTP-TCP链接的创建与断开

HTTP报文

HTTP协议报文是应用程序之间发送的数据块,也就是客户端和服务端用于交互的信息。客户端的报文叫作请求报文,服务器端的报文叫作响应报文。

HTTP报文组成

HTTP报文由起始行、首部和实体的主体(也称报文主体或主体)组成。起始行和首部以一个回车符和换行符做为结束,主体部分能够是二进制数据,也能够为空。

HTTP报文组成

1. 起始行

请求报文起始行:

请求报文起始行说明了要作什么,由请求方法 、请求URI和协议版本构成。

GET /index.html HTTP/1.1

响应报文起始行:

响应报文的起始行,由协议版本、状态码和缘由短语构成。

HTTP/1.1 200 OK   // OK就是缘由短语

HTTP-请求-响应报文

2. 首部

首部字段分类

  • 1.通用首部

    客户端和服务端均可以使用的首部

    通用首部字段表:

    通用首部字段

  • 2.请求首部

    请求报文特有的首部,为服务器提供了一些额外的信息,补充了请求的附加内容、客户端信息、响应内容相关的优先级等信息。

    请求首部字段
    请求首部字段

  • 3.响应首部

    响应报文特有的字段

    响应首部字段表:

    响应首部字段

  • 4.实体首部

    用于针对请求报文和响应报文主体部分使用的首部

    实体首部字段

  • 5.扩展首部

    扩展首部是非标准的首部,由应用程序开发者建立,但还未添加到已批准的HTTP标准中去。

http状态码

状态码的职责是当客户端向服务器端发送请求时,描述返回的请求结果。借助状态码,用户能够知道服务器端是正常处理了请求,仍是出现了错误。

状态码分类:

状态码区间 类别
100~199 信息性状态码
200~299 成功状态码
300~399 重定向状态码
400~499 客户端错误状态码
500~599 服务器错误状态码

经常使用状态码列表:

状态码 缘由短语 含义
200 OK 表示从客户端发来的请求在服务器端被正常处理了
204 No Content 该状态码表明服务器接收的请求已成功处理,但在返回的响应报文中不含实体的主体部分。另外,也不容许返回任何实体的主体。
301 Moved Permanently 永久重定向,该状态码表示请求的资源已被分配了新的 URI,之后应使用资源如今所指的 URI
302 Found 临时性重定向,该状态码表示请求的资源已被分配了新的 URI,但愿用户(本次)能使用新的 URI 访问
303 See Other 303 状态码和 302 Found 状态码有着相同的功能,但 303 状态码明确表示客户端应当采用 GET 方法获取资源,这点与 302 状态码有区别
304 Not Modified 缓存
307 Temporary Redirect 临时重定向,和302同样
400 Bad Request 该状态码表示请求报文中存在语法错误。当错误发生时,需修改请求的内容后再次发送请求。另外,浏览器会像 200 OK 同样对待该状态码
401 Unauthorized 该状态码表示发送的请求须要有经过 HTTP 认证(BASIC 认证、DIGEST 认证)的认证信息
403 Forbidden 该状态码代表对请求资源的访问被服务器拒绝了
404 Not Found 该状态码代表服务器上没法找到请求的资源
500 Internal Server Error 该状态码代表服务器端在执行请求时发生了错误。也有多是 Web应用存在的 bug 或某些临时的故障
502 Bad Gateway 网关错误
503 Service Unavailable 该状态码代表服务器暂时处于超负载或正在进行停机维护,如今没法处理请求。若是事先得知解除以上情况须要的时间,最好写入RetryAfter 首部字段再返回给客户端

HTTP中不一样场景下,首部字段的做用

1. CORS 跨域资源共享

跨域资源共享( CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin (domain) 上的Web应用被准许访问来自不一样源服务器上的指定的资源。当一个资源从与该资源自己所在的服务器不一样的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。 --MDN

下面使用nodejs来搭建一个简单的服务器,来介绍一个跨域问题的解决方法

// index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>CORS</title>
</head>
<body>
    Hello World
<script>
    fetch('http://127.0.0.1:8081')
</script>
</body>
</html>
// server.js

const http = require('http')

http.createServer(function(req, res) {
    res.writeHead('200', {   
        'Access-Control-Allow-Origin': 'http://localhost:8082'
    })
}).listen(8081)

在源地址为 http://localhost:8082 下,请求http://localhost:8081,是跨域请求,浏览器会自动在request Header中发送Origin首部字段,并把值设置为来自哪一个源,本例为http://localhost:8082。服务器须要在响应头中设置Access-Control-Allow-Origin,来告知浏览器能够处理返回的数据。若是响应头中不设置Access-Control-Allow-Origin则会报错,可是返回状态码为200,跨域其实是浏览器自己的一个安全机制。

http-跨域-报错

http-跨域-状态码200

// server2.js
// 启动8082端口服务,在浏览器中访问http://127.0.0.1:8082,会返回index.html内容

const http = require('http')
const fs = require('fs')
http.createServer(function(req, res) {
    var page = fs.readFileSync('index.html', 'utf-8')
    res.writeHead(200, {
        'Content-Type': 'text/html'
    })
    res.end(page)
}).listen(8082)

关于CORS跨域请求的分类:

1.简单请求:

须要同时知足如下的条件就是简单请求

(1)请求方法:

GET、POST、HEAD

(2)请求头不能为如下其余字段以外

Accept
Accept-Language
Content-Language
Content-Type的值必须为application/x-www-form-urlencoded、multipart/form-data、text/plain之一

2.非简单请求:

非简单请求是当请求信息不知足简单请求的条件,浏览器就发送方法为OPTIONS的预请求,包含本身请求的方法及须要使用的请求头字段,在获得服务器响应容许以后,浏览器会按照想要使用的请求方法及头信息再发一次请求。

如今修改如下上面的例子:

// index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>CORS</title>
</head>
<body>
    Hello World
<script>
    fetch('http://127.0.0.1:8081', {
        method: 'PUT',
        headers: {
            X-Coustom-Head: 'abc'
        }
    })
</script>
</body>
</html>
// server.js

const http = require('http')

http.createServer(function(req, res) {
    res.writeHead('200', {   
        'Access-Control-Allow-Origin': 'http://localhost:8082'
    })
}).listen(8081)

若是服务端不进行相应的设置告诉浏览器容许跨域访问则会报错

HTTP-cors-methodError

可是预请求返回状态码为200
HTTP-cors-options-状态码200

// server2.js
// 启动8082端口服务,在浏览器中访问http://127.0.0.1:8082,会返回index.html内容

const http = require('http')
const fs = require('fs')
http.createServer(function(req, res) {
    var page = fs.readFileSync('index.html', 'utf-8')
    res.writeHead(200, {
        'Content-Type': 'text/html'
    })
    res.end(page)
}).listen(8082)

如今咱们修改如下 server.js

// server.js

const http = require('http')

http.createServer(function(req, res) {
    res.writeHead('200', {   
        'Access-Control-Allow-Origin': 'http://localhost:8082',
        'Access-Control-Allow-Headers': 'X-Coustom-Head',
        'Access-Control-Allow-Methods': 'PUT'
    })
}).listen(8081)

从新启动node服务,访问http://locaohost:8082,能够看到在发送预请求后,浏览器会继续发送PUT请求

HTTP-cors-options

HTTP-cors-allow.png

关于CORS的其余设置这里就很少作介绍了,这里主要是用一个例子来讲明如下http不一样字段在跨域场景下的做用。

2. 缓存 (Cache-Control的做用)

本例依旧用node服务来说解一下Cache-Control的做用,新建三个文件

// index.html
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Cache-Control</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>
    <script src="/script.js"></script>
</body>

</html>
// script.js
console.log('script.js')
// server.js
const http = require('http')
const fs = require('fs')


http.createServer(function(req, res) {
    if (req.url === '/') {
        let page = fs.readFileSync('index2.html', 'utf-8')
        res.writeHead(200, {
            'Content-Type': 'text/html'
        })
        res.end(page)
    }

    if (req.url === '/script.js') {
        let page = fs.readFileSync('script.js', 'utf-8')
        res.writeHead(200, {
            'Content-Type': 'text/javascript',
            'Cache-Control': 'max-age=10'
        })
        res.end(page)
    }
}).listen(8082)

在第一次请求script.js资源时,向服务器发送请求

HTTP-cache-control-1
HTTP-cache-control-3

因为服务器返回响应时,设置Cache-Control: 'max-age=10'时,修改script.js后,在10秒内继续请求script.js资源,则从缓存中读取,而打印信息依旧是'script.js'

// script.js
console.log('script-modify.js')

HTTP-cache-control-1
HTTP-cache-control-3

更多关于缓存的知识在这里也很少介绍了,贴两张cache-control字段在请求和响应时能够设置的值和其表示含义:

1. Cache-Control 缓存请求指令:

HTTP-cache-control-缓存请求指令

2. Cache-Control 缓存响应指令:

HTTP-cache-control-缓存响应指令

3. cookie

指某些网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据(一般通过加密),当下次再访问时浏览器会将该网站的cookie发回给服务器端。

cookie若是不设置过时时间,随浏览器关闭而失效,若是有须要能够设置过时时间,继续上代码例子🌰,新建两个文件以下

// index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Cookie</title>
</head>
<body>
    Cookie
<script>
    console.log(document.cookie)
</script>
</body>
</html>
// server.js

const http = require('http')
const fs = require('fs')

http.createServer(function(req, res) {
    if (req.url === '/') {
        let page = fs.readFileSync('index.html', 'utf-8')
        res.writeHead(200, {
            'Content-Type': 'text/html',
            'Set-Cookie': ['a=1;max-age:5', 'b=2;HTTPOnly']
        })
        res.end(page)
    }
}).listen(8082)

启动node服务,访问localhost:8082,能够看到成功设置了cookie

HTTP-cookie-application

并在响应头信息中设置了Set-Cookie字段

HTTP-cookie-init

另外关注如下打印信息,发现只有a=1,由于给b=2设置了HttpOnly属性,不容许JavaScript经过脚原本获取到cookie信息

HTTP-cookie-console

因为当再次请求时,cookie会在请求头中发送到服务器,因为cookie a=1设置了5秒后过时,在5秒后刷新页面,请求头中的cookie只有a=1

    HTTP-cookie-againRequest

在5秒内发送二次请求,cookie a=1没有失效,在请求头中cookie a=1;b=2都会发送到服务器

    HTTP-cookie-max-age

另外对于cookie的其余设置如expires、domain等在这里也很少作介绍了

4. 重定向

当服务端返回30一、30二、307等状态码都表明资源已经被重定向到其余位置,301表示永久改变URI,302和307表示临时重定向到某个URI

本例举一个服务器返回302状态码的例子,直接上代码:

// server.js

const http = require('http');
const fs = require('fs')

http.createServer((req, res) => {
    if (req.url === '/') {
        res.writeHead(302, {
            'Location': '/redirect'
        })
        res.end()
    }

    if (req.url === '/redirect') {
        res.end('redirect')
    }
}).listen(8082);

访问localhost:8082, 服务器返回302状态码时,在相应头中设置Location首部字段,浏览器会继续发送请求到重定向的地址

HTTP-重定向-302-1

HTTP-重定向-302-2

HTTP与HTTPS的区别

首先说一下什么是HTTPS

HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer 或 Hypertext Transfer Protocol Secure,超文本传输安全协议),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。即HTTP下加入SSL层,HTTPS的安全基础是SSL,所以加密的详细内容就须要SSL。 --百度百科

HTTPS = HTTP+ 加密 + 认证 + 完整性保护

最主要是在应用层和传输层中间加了一个SSL(安全套阶层),一般,HTTP 直接和 TCP 通讯。当使用 SSL 时,则演变成先和 SSL 通讯,再由 SSL 和 TCP 通讯。

HTTP-http与https对比

HTTP与HTTPS的区别:

  • (1) HTTP是明文传输,HTTPS是通过SSL加密后进行传输,只有客户端和服务端根据公钥和私钥进行加密和解密能看到,中间任何传输环节没法获取传输信息,因此HTTPS比HTTP安全
  • (2) HTTPS须要到数字证书认证机构进行购买
  • (3) HTTP服务器默认端口是80,HTTPS服务器默认端口是443

本文主要介绍HTTP,关于HTTPS主要就介绍这么多吧。

HTTP2

本想说点HTTP2的知识,奈何本身是小白,放个百度百科的连接吧 HTTP2

等后续随着不断的学习,再回来更新本文。

另外放一个HTTP1.1与HTTP2请求与相应对比的demo的连接HTTP/2 is the future of the Web, and it is here!

最后,本文主要介绍了一些HTTP在web开发中的基础知识,关于概念和图解流程的截图基本上都是来自《TCP/IP详解 卷1:协议》《图解HTTP》《HTTP权威指南》,可放心参考。笔者功力实在有限,若有问题,请你们多多指出,相互学习和进步,也但愿经过个人学习与实践过程,整理出的笔记能对你们有所帮助,谢谢。

本文参考连接:

TCP/IP详解 卷1:协议
图解HTTP
HTTP权威指南
跨域资源共享 CORS 详解--阮一峰

相关文章
相关标签/搜索