掌握HTTP协议是Web开发最基础的一环,然而很多程
掌握HTTP协议是Web开发最基础的一环,然而很多程序猿对于HTTP协议基本不了解,或者只了解其中狭小的一部分,导致很多程序猿无法快速成长,陷入重复coding的地狱。这个项目从原理到实践,用完整的例子展示HTTP协议的各个环节,包含网络分层模型、TCP和HTTP的关系、HTTP数据包构成、头行信息的定义、数据传输类型、缓存和资源校验、Cookie和Session、各种非常有意义的Header、Nginx使用和代理、缓存配置、HTTPS服务的意义和使用、HTTP2的定义和实现等,帮助您提高对HTTP内容的理解,快速成长。
内容介绍
HTTP不存在连接这个概念,它只要请求和响应这么一个概念,请求和响应都是数据包它们之间是要通过一个数据传输的通道的,就在TCP里面创建了一个从客户端发起到服务端的连接
为什么需要三次握手?
为了防止服务端开启一些无用的连接,造成浪费。因为网络传输是有延迟的。如果客户端发起连接请求服务端就直接创建了连接返回内容给客户端,但因为某种原因造成数据包丢失,客户端就会一直没有接受到服务器返回的数据,客户端可能设置了超时就关闭了,客户端再发起一个新的创建连接的请求,这个时候服务端是不知道客户端是否接受到服务端第一次返回的信息,服务端的端口就会一直开着等着客户端发送请求数据,这个时候服务端的开销就浪费了。
URI、URL和URN URI 统一资源标志符,包含URL、URN URL 统一资源定位符 URN 永久统一资源定位符 HTTP报文格式curl baidu.com
curl www.baidu.com
curl -v www.baidu.com
CORS跨域请求的限制与解决
浏览器在发送请求的时候并不知道是否跨域,所以请求是可以发出的,也会接收服务端返回的内容,只不过浏览器在看到response header里没有Access-Control-Allow-Origin这个属性并且设置为允许,浏览器会把请求返回的内容忽略掉并且在console里面报错No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8888' is therefore not allowed access.
具体实例
const http = require('http')
http.createServer((request, response) => {
console.log(request.url);
response.writeHead(200, {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'X-Test-Cors',
'Access-Control-Allow-Methods': 'POST, PUT, Delete',
'Access-Control-Max-Age': '100', //代表多少秒
})
response.end('2222')
}).listen(8887)
console.log('server listening 8887');
预请求验证
跨域限制是为了保证服务端安全,浏览器在发送跨域请求时会先发送一个options请求来获得服务端允许的认可,然后再实际发送对应的请求(如post, get等)
跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP 认证相关数据)。具体描述详见HTTP访问控制(CORS)
缓存头Cache-Control的含义和使用 可缓存性常用 cache-directive 值
public 所有内容都将被缓存(客户端和代理服务器都可缓存) private 内容只缓存到私有缓存中(仅客户端可以缓存,代理服务器不可缓存) no-cache 任何一个节点都不进行缓存到期
max-age= 在 xxx 秒后,浏览器重新发送请求到服务器 s-maxage= 会代替max-age,但是只有在代理服务器里面才会生效 max-stale= 只要在这个时间内,还可以使用过期的缓存而不需要去服务器请求新的内容。这个属性在发起端设置才有用,在服务端返回的内容中设置这个属性没有用重新验证
must-revalidate 如果缓存的内容失效,请求必须发送到服务器/代理以进行重新验证 proxy-revalidate 如果缓存的内容失效,请求必须发送到服务器/代理以进行重新验证其他
no-store 所有内容都不会被缓存到缓存或 Internet 临时文件中 no-transform实例
<!DOCTYPE html>
<html lang="en">
<body>
<script src="./script.js"></script>
</body>
</html>
如上代码,当在浏览器中运行,打开Network选项卡,刷新页面后会看到每次script.js文件都加载了
当我们在服务端配置了Cache-Control
属性,具体代码如下
const http = require('http')
const fs = require('fs')
http.createServer(((request, response) => {
if (request.url == '/') {
const html = fs.readFileSync('test.html', 'utf8')
response.writeHead(200, {
'Content-type': 'text/html'
})
response.end(html)
}else if (request.url == '/script.js') {
response.writeHead(200, {
'Content-type': 'text/javascript',
'Cache-Control': 'max-age=10'
})
response.end('console.log("script loaded")')
}
})).listen(8888)
console.log('server listening on 8888')
我们在header中写入了'Cache-Control': 'max-age=10'
,意思就是缓存十秒。然后再刷新页面,就会发现十秒内如果我们不更换url的话,浏览器中的Network选项卡显示如下
可以看到请求时间为0,尺寸显示为from memory cache,就是从缓存中读取的文件,这样可以有效提升效率.
但是也会带来一些问题,比如服务端的代码已经变了,但以为此时浏览器还是从缓冲中读取的数据,就会导致无法及时获得服务端的更新。常见的前端解决方案,我们会根据文件内容给文件名加上一段hash码,如果js中的内容没有变,它的hash码就不会变,反应到页面就是资源的url没有变,那么我就可以使用静态资源缓存。如果js中的内容发生变化,它的hash码就会变,也就是url变了,就会发起一个新的静态资源请求,而不是使用缓存中的内容。这样就可以达到一个更新缓存的目的。
缓存验证Last-Modified和Etag的使用版权声明:
1、该文章(资料)来源于互联网公开信息,我方只是对该内容做点评,所分享的下载地址为原作者公开地址。2、网站不提供资料下载,如需下载请到原作者页面进行下载。