http报文结构
TCP:TCP头+数据部分
- HTTP:也是header+body结构,具体而言就是:起始行+头部+空行+实体 起始行:
- GET /home HTTP/1.1----方法+路径+http版本---请求报文
- HTTP/1.1 200 OK-----http版本+状态码+原因----响应报文---该起始行也叫状态行
头部:(字段过多不一一介绍)
头部字段格式: 字段名不区分大小写 字段名不允许出现空格,不可以出现下划线_ 字段名后面必须紧接着:
空行:(用来区分头部和实体) 空行后的内容全部视为实体
实体: 就是具体的数据部分,请求报文对应请求体,响应报文对应响应体
http的请求方法
有哪些方法:
- GET: 通常用来获取资源
- HEAD: 获取资源的元信息
- POST: 提交数据,即上传数据
- PUT: 修改数据
- DELETE: 删除资源(几乎用不到)
- CONNECT: 建立连接隧道,用于代理服务器
- OPTIONS: 列出可对资源实行的请求方法,用来跨域请求
- TRACE: 追踪请求-响应的传输路径
get\post的区别:
- 从缓存的角度,GET 请求会被浏览器主动缓存下来,留下历史记录,而 POST 默认不会。
- 从编码的角度,GET 只能进行 URL 编码,只能接收 ASCII 字符,而 POST 没有限制。
- 从参数的角度,GET 一般放在 URL 中,因此不安全,POST 放在请求体中,更适合传输敏感信息。
- 从幂等性的角度,GET是幂等的,而POST不是。(幂等表示执行相同的操作,结果也是相同的)
- 从TCP的角度,GET 请求会把请求报文一次性发出去,而 POST 会分为两个 TCP 数据包,首先发 header 部分,如+ 果服务器响应 100(continue), 然后发 body 部分。(火狐浏览器除外,它的 POST 请求只发一个 TCP 包)
如何理解URI
- URI:统一资源标识符,作用区分网络上不同的资源,类似身份证,表示资源的唯一性
- URI:URL+URN
- URI结构:这个URI中,https即scheme部分(协议名),www.baidu.com为host:port部分(主机名和端口) (注意,http 和 https 的默认端口分别为80、443), /s为path部分(请求路径),而wd=HTTP&rsv_spt=1就是query部分(查询参数)
http状态码的理解
- 1xx: 表示目前是协议处理的中间状态,还需要后续操作。(100post请求)
- 2xx: 表示成功状态。(200)
- 3xx: 重定向状态,资源位置发生变动,需要重新请求。(304协商缓存)
- 4xx: 请求报文有误。(405请求方法不被服务器允许,404资源未找到)
- 5xx: 服务器端发生错误。(500)
http的特点和缺点
特点:
-
灵活可扩展,主要体现在两个方面。一个是语义上的自由,只规定了基本格式,比如空格分隔单词,换行分隔字段,其他的各个部分都没有严格的语法限制。另一个是传输形式的多样性,不仅仅可以传输文本,还能传输图片、视频等任意数据,非常方便。
-
可靠传输。HTTP 基于 TCP/IP,因此把这一特性继承了下来。这属于 TCP 的特性,不具体介绍了。
-
请求-应答。也就是一发一收、有来有回, 当然这个请求方和应答方不单单指客户端和服务器之间,如果某台服务器作为代理来连接后端的服务端,那么这台服务器也会扮演请求方的角色。
-
无状态。这里的状态是指通信过程的上下文信息,而每次 http 请求都是独立、无关的,默认不需要保留状态信息。 缺点:
-
无状态 所谓的优点和缺点还是要分场景来看的,对于 HTTP 而言,最具争议的地方在于它的无状态。 在需要长连接的场景中,需要保存大量的上下文信息,以免传输大量重复的信息,那么这时候无状态就是 http 的缺点了。 但与此同时,另外一些应用仅仅只是为了获取一些数据,不需要保存连接上下文信息,无状态反而减少了网络开销,成为了 http 的优点。
-
明文传输 即协议里的报文(主要指的是头部)不使用二进制数据,而是文本形式。 这当然对于调试提供了便利,但同时也让 HTTP 的报文信息暴露给了外界,给攻击者也提供了便利。WIFI陷阱就是利用 HTTP 明文传输的缺点,诱导你连上热点,然后疯狂抓你所有的流量,从而拿到你的敏感信息。 队头阻塞问题 当 http 开启长连接时,共用一个 TCP 连接,同一时刻只能处理一个请求,那么当前请求耗时过长的情况下,其它的请求只能处于阻塞状态,也就是著名的队头阻塞问题。
Accept系列字段了解
Accept系列字段的介绍分为四个部分: 数据格式、压缩方式、支持语言和字符集。
定长和不定长数据,http怎么传输
定长:对于定长包体而言,发送端在传输的时候一般会带上 Content-Length, 来指明包体的长度。例如:res.setHeader('Content-Length', 10);只允许传递的数据只能为10个字节,超过10个就会被截取,例如res.write("1234567890");--显示1234567890,若res.write("12345678901234");---输出也是1234567890,后面的超出部分实际上在http的响应体中直接被截取了 不定长包体:http头部字段:Transfer-Encoding: chunked会进行数据的分块传输。设置了该字段后会有下面两个效果:基于长连接持续推送动态内容、Content-Length 字段会被忽略,例子:
const http = require('http');
const server = http.createServer();
server.on('request', (req, res) => {
if(req.url === '/') {
res.setHeader('Content-Type', 'text/html; charset=utf8');
res.setHeader('Content-Length', 10);
res.setHeader('Transfer-Encoding', 'chunked');
res.write("<p>来啦</p>");
setTimeout(() => {
res.write("第一次传输<br/>");
}, 1000);
setTimeout(() => {
res.write("第二次传输");
res.end()
}, 2000);
}
})
server.listen(8009, () => {
console.log("成功启动");
})
//实现效果是,设置的Content-Length不起作用,即res返回的是什么就输出什么。
//效果2:打开地址首先看到来啦,隔1s后显示第一次传输,再隔1后显示第二次传输,实现长连接
实现长连接就是头部添加了Connection: keep-alive这个字段来维持长连接。
http如何处理大文件的传输
采取范围请求的方案,允许客户端仅仅请求一个资源的一部分。 服务器添加一个Accept-Ranges: none响应体来告诉客户端服务端支持范围请求。 Range 字段拆解:看客户端指定的是那部分
http如何处理表单数据提交
在http有两种表单的提交方式(对post请求提交表单),体现为两种不同的Content-Type取值: application/x-www-form-urlencoded multipart/form-data(主要采用的方式)
总结: multipart/form-data 格式最大的特点在于:每一个表单元素都是独立的资源表述。另外,你可能在写业务的过程中,并没有注意到其中还有boundary的存在,如果你打开抓包工具,确实可以看到不同的表单元素被拆分开了,之所以在平时感觉不到,是以为浏览器和 HTTP 给你封装了这一系列操作。 而且,在实际的场景中,对于图片等文件的上传,基本采用multipart/form-data而不用application/x-www-form-urlencoded,因为没有必要做 URL 编码,带来巨大耗时的同时也占用了更多的空间。
如何解决http1.1的队头阻塞问题
队头阻塞:http传输发送的时候,发送的任务被放在一个任务队列串行执行,一旦队首的请求处理太慢,就会阻塞后面请求的处理。
解决办法:
- (1)并发连接,提高http请求的数量提高并发连接。相当于增加任务队列,增加队列数,在谷歌浏览器中最多并发6个连接。
- (2)域名分片:多分几个域名,例如比如 content1.sanyuan.com 、content2.sanyuan.com。这样一个sanyuan.com域名下可以分出非常多的二级域名,而它们都指向同样的一台服务器,能够并发的长连接数更多了,事实上也更好地解决了队头阻塞的问题
cookie的了解
因为http的无状态协议,因为http是一发一回所以不需要维持状态浪费内存,正因为http的无状态协议,每次http请求都是独立的,默认不需要保留状态,但如果有需要保存状态的时候就使用到cookie了。 cookie本质上是浏览器存储的一个很小的文本文件,通过键值对的方式存储。对同一个域名下发送请求,都会携带相同的cookie,服务端拿到cookie进行解析,便能拿到客户端的状态。而服务端可以通过响应头的set-cookie字段对客户端写入cookie。
Cookie属性:
- (1)cookie有效期可以通过Expires和Max-Age(单位是秒,从浏览器收到报文开始计算)两个属性来设置。若cookie过期,则会把cookie删除并不会发生给服务器。
- (2)作用域:Domain和path,是给cookie绑定域名和路径,若发送请求前,发现域名或者路径不匹配,就不会携带cookie。Domian主要是对某个域名绑定,例如对静态资源的域名不携带cookie等操作,只设置动态资源的域名就可以实现。
- (3)安全相关:如果cookie带上secure说明是https请求才会携带cookie;若cookie带上httponly,说明不能通过js访问,防止xss攻击。sameSite属性是防止csrf攻击的,默认的值是none,请求会自动携带cookie,设置值为Strict时候,浏览器会禁止第三方请求携带cookie,比如sanyuan.com网站只能在sanyuan.com域名当中请求才能携带cookie,在其他网站请求都不能。
Cookie的缺点:
- (1)cookie的大小上限只有4kb,只能存储少量的信息
- (2)性能缺陷:cookie紧跟域名,不管域名下某个地址是否需要cookie都会携带,这样就会导致请求数多的时候就会造成带宽的浪费。可以通过Domain和path指定作用域解决。
- (3)安全缺陷:cookie以纯文本的形式在浏览器和服务器中传递,很容易被获取,然后进行一些改动。另外,在cookie的httponly为false的时候,可以通过js脚本获取cookie信息。
http代理
因为HTTP 是基于请求-响应模型的协议,一般由客户端发请求,服务器来进行响应。 但是特殊特殊情况就是代理服务器的情况:引入代理之后(正向代理),作为代理的服务器相当于一个中间人的角色,对于客户端而言,表现为服务器进行响应;而对于源服务器,表现为客户端发起请求,具有双重身份。
http代理的作用:
- (1)负载均衡:根据随机算法、轮询、一致性hash等算法把请求分发到不同的原服务器中,减少服务器压力。
- (2)保障安全:利用心跳机制监控后台服务器,一旦发现故障就会剔除。并且还有对数据过滤、非法ip限流等都是代理服务器的工作。
- (3)缓存代理:将内容缓存到代理服务器,使得客户端可以直接从代理服务器获取。
如何理解http缓存和缓存代理
http缓存:
首先通过 Cache-Control 验证强缓存是否可用 如果强缓存可用,直接使用 否则进入协商缓存,即发送 HTTP 请求,服务器通过请求头中的If-Modified-Since或者If-None-Match这些条件请求字段检查资源是否更新 若资源更新,返回资源和200状态码 否则,返回304,告诉浏览器直接从缓存获取资源 代理缓存:
代理服务器接管一部分的服务端的http缓存,客户端缓存过期后就近到代理缓存中获取,代理缓存过期后才请求源服务器,降低源服务器压力。 Cache-Control: public, max-age=1000, s-maxage=2000 这个响应是允许代理服务器缓存的,客户端缓存过期了到代理中拿,并且在客户端的缓存时间为 1000 秒,在代理服务器中的缓存时间为 2000 s。
跨域是什么,浏览器如何拦截响应,如何解决
浏览器遵循同源策略(协议、主机和端口都相同视为同源),非同源有下面限制: 不能读取和修改对方的 DOM 不读访问对方的 Cookie、IndexDB 和 LocalStorage 限制 XMLHttpRequest 请求。
跨域请求:浏览器想目标URI发ajax请求时,只要当前URL和目标的URL不同源,就会产生跨域。 浏览器拦截响应:就是说浏览器主进程会发起请求,但是浏览器主进程会把服务端处理完的返回的响应体全部丢掉,不发给渲染进程。
解决跨域:
- (1)cors:全程是跨域资源共享。需要浏览器和服务器的共同支持。
- (2)jsonp:使用script标签的不跨越技巧,通过src填写目标地址从而发起get请求,实现跨域请求并拿到响应。jsonp的优势比cors兼容性好,缺点只支持ge请求。
- (3)nginx:nginx是一种高性能反向代理服务器,可以轻松解决跨域问题。
正向代理:帮助客户端访问客户端访问不到的服务器,然后把结果返回给客户端。 反向代理:负责拿到客户端的请求,将请求转发给其他的服务器,主要的场景是维持服务器集群的负载均衡。 两者区别:正向代理是帮客户端做事情,反向代理是帮服务器做事情。 nginx解决跨域:
server {
listen 80;
server_name client.com;//客户端访问的地址
location /api {
proxy_pass server.com;//代理的地址
}
}
Http/2有哪些改进
http/2性能提升的两点:
- (1)头部压缩:对于get请求,请求报文几乎全是请求头,存在优化空间,http2针对头部字段,采用对应的压缩算法(HPACK)。该算法的2个亮点:首先就是服务器和客户端之间建立哈希表,将用到的字段存放在这张表中,在传输的时候对之前出现的值,只需要把索引传给对方,对方根据索引查询表就可以获取对应的数据。这种传索引的方式,可以让请求头字段很大程度的精简和复用。其次就是对于证书和字符串进行哈夫曼编码,该编码原理就是先将所有出现的字符建立一张索引表,然后让出现次数多的字符对应的索引尽可能的短,传输的时候也是传输这样的索引序列,可以达到很高的压缩率。
- (2)多路复用
- (3)设置请求优先级
- (4)服务器推送 多路复用:
- 解决队头阻塞:HTTP 队头阻塞的问题,其根本原因在于HTTP 基于请求-响应的模型,在同一个 TCP 长连接中,前面的请求没有得到响应,后面的请求就会被阻塞。后面使用并发连接和域名分片的方式解决,也没有从http本身层面解决问题,只是增加tcp连接分摊出现的几率而已。
- 二进制分帧:将报文全部换成二进制格式,全部传输01串,方便机器解析。原来的header+body的报文格式被拆分成一个个二进制的帧,用header帧存放头部字段,data帧存放请求体数据。分帧之后,服务器看到的不再是一个个完整的HTTP请求报文,而是一对乱序的二进制帧,服务器会根据每个帧的stream id来组装成一个完整的请求报文和响应报文。这些帧不存在先后顺序,因此不需要排队等待,解决了队头阻塞问题。
- 通信双方都可以给对方发送二进制帧,这种二进制帧的双向传输的序列,叫流。http2用流来在一个tcp连接上来进行多个数据帧的通信,这就是多路复用的概念。
服务器推送:服务器只能推送静态资源给客户端。