Http协议及TCP

目录

1.   了解部分有意义的头部信息

2.    页面如何到达浏览器并展现给用户

3.   网络协议分层

4.   HTTP/1.1

5.  三次握手

6.   统一资源定位器  Uniform Resource Locators

7.   创建一个最简单的web服务

8.   跨域请求

9.  缓存Cache-Control: (哈希值用于刷新浏览器缓存)

10. Cookie和Session

11.  数据协商

12.   Content Security Policy (内容安全策略)

13. nginx设置代理缓存

14. nginx缓存验证头信息

15. https

16. nginx部署https服务

17. http2


1.   了解部分有意义的头部信息

头部信息
Catch-Control:max-age=100静态资源缓存100s
Content-Type,Content-Encoding 等用来约束数据类型
Cookie   保持会话信息
CORS 实现跨域并保持安全性限制

2.    页面如何到达浏览器并展现给用户

Redirect(跳转)--> App catch(应用缓存)-->DNS(DNS查找)-->TCP (创建TCP链接)-->Request(发送请求)

-->Response(接受响应)

1. redirect : 对于浏览器已经记录过的301请求,直接跳转,属于纯客户端的行为。

2. cache: 根据资源是否有设置cache control ,然后判断缓存。如果超时则要重新请求缓存。

3. DNS查询:当通过浏览器请求一个web页面,浏览器会创建一个线程去处理这个请求,随后开始远程dns查找,远程dns服务器会将输入的URL对应的IP地址返回给浏览器。(DNS域名系统)

4. TCP连接: 三次握手 (HTTP请求是在TCP连接上发送的,一个TCP连接可以发送多个HTTP请求)

5. 发送请求: 数据经过代理服务器或代理服务器缓存直接读取。浏览器通过连接发送一个HTTP GET请求到Web服务端。

6. 接受响应。Web服务端找到请求的资源,然后在HTTP响应中将其返回,状态200表示响应正常。

常用状态码:

  • 200: 服务端成功响应
  • 301: 永久重定向
  • 302: 临时重定向
  • 403: 请求被拒绝
  • 404: 服务端找不到请求的资源
  • 500: 处理请求时出错
  • 503: 服务不可用
  • 504: 网关超时

   最后,浏览器收到页面HTML,就开始解析并渲染页面内容

3.   网络协议分层

经典的五层网路模型:

 物理层:定义物理设备如何传输数据(电脑硬件,网卡端口,光缆...)。

数据链路层: 在通信的实体间建立数据链路连接。

网络层:为数据在节点之间传输创建逻辑链路。

传输层: 向用户提供可靠的端对端(end-to-end)服务。更多情况下实用TCP/IP协议传输数据。

              定义如何传输数据,传输数据的方式。

应用层:为应用软件提供了很多的服务。构建于TCP协议之上。

4.   HTTP/1.1

持久连接:一个连接中在发送的请求后不关闭

pipeline: 可以通过声明,在同一个连接里发送多个请求

增加host:可以在同一台物理服务器跑多个不同的web服务

HTTP 2 : 所有数据以二进制传输,同一个连接里发送多个请求不再需要按照顺序,头信息压缩以及推送等提高效率的功能。

推送功能(请求html的同时,可以将html中需要引用到的JavaScript文件和css文件推送到客户端,实现html和css js文件的发送顺序是闭型的,提高整体的传输效率)

5.  三次握手

三次:为了验证服务端和客户端收发功能正常,防止服务端开启无用的连接。(网络服务器延迟等)

浏览器通过与远程web服务端的三次握手来建立一个TCP/IP请求。这个握手由浏览器与远程服务端之间的SYN(标志位),SYN-ACK,ACK消息组成。(SYN:同步序列编号)

                                                图1  TCP 三次握手

6.   统一资源定位器  Uniform Resource Locators

scheme://host.domain:port/path/filename

说明:

  • scheme - 定义因特网服务的类型。最常见的类型是 http
    • host - 定义域主机(http 的默认主机是 www)
    • domain - 定义因特网域名,比如 runoob.com
    • :port - 定义主机上的端口号(http 的默认端口号是 80)
    • path - 定义服务器上的路径(如果省略,则文档必须位于网站的根目录中)。
    • filename - 定义文档/资源的名称

7.   创建一个最简单的web服务

server.js文件下创建如下内容: 

const http = require('http')

http.createServer((request, response) => {
  console.log('request', request.url)

  response.end('123')
}).listen(8888)

console.log('server listening on 8888')

启动: node server.js

浏览器打开:localhost:8888, 查看内容

利用curl命令查看http报文信息

$ curl -v www.baidu.com

能得到报文头和header的内容:

 * Rebuilt URL to: www.baidu.com/
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0*                                                                                                                   Trying 14.215.177.39...
* TCP_NODELAY set
* Connected to www.baidu.com (14.215.177.39) port 80 (#0)
> GET / HTTP/1.1
> Host: www.baidu.com
> User-Agent: curl/7.57.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Accept-Ranges: bytes
< Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform
< Connection: Keep-Alive
< Content-Length: 2381
< Content-Type: text/html
< Date: Fri, 17 Aug 2018 05:07:47 GMT
< Etag: "588604cf-94d"
< Last-Modified: Mon, 23 Jan 2017 13:27:43 GMT
< Pragma: no-cache
< Server: bfe/1.0.8.18
< Set-Cookie: BDORZ=27315; max-age=86400; domain=.baidu.com; path=/
<
{ [1048 bytes data]
100  2381  100  2381    0     0   2381      0  0:00:01 --:--:--  0:00:01 74406

8.   跨域请求

新建server.js: 创建请求

//在8888端口中请求了一个8887端口的内容

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

http.createServer((request, response) => {  //创建请求
  console.log('request', request.url)

  const html = fs.readFileSync('test.html', 'utf8');  //同步读取html内容
  response.writeHead(200, {
    'Content-Type': 'text/html'
  })

  response.end(html)  //响应内容
}).listen(8888)

console.log('server listening on 8888')

server2.js

const http = require('http')

http.createServer((request, response) => {
  console.log('request', request.url)

  // 允许跨域请求  写返回的状态
  response.writeHead(200, {
    'Access-Control-Allow-Origin': '*',
  })

  response.end('123')
}).listen(8887)

console.log('server listening on 8887')

test.html 中向8887端口发送请求:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>test</title>
</head>
<body>
  <script>
    var xhr = new XMLHttpRequest()
    xhr.open('GET', 'http://127.0.0.1:8887/')
    xhr.send()
  </script>
</body>
</html>

发送预请求:(跨域限制:保证服务端的安全)

预请求
允许的方法GRT、POST、HEAD
允许Content-Type

text/plain、multipart/formdata、

application/x-www-form-urlencoded

通过options请求获得服务器的认可

server.js:

//相当于在8888端口中请求了一个8887端口的内容

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

http.createServer((request, response) => {  //创建请求
  console.log('request', request.url)

  const html = fs.readFileSync('test.html', 'utf8');  //同步读取html内容
    response.writeHead(200, {
      'Content-Type': 'text/html'
    })
  response.end(html)  //响应内容

}).listen(8888)

console.log('server listening on 8888')

server2.js:

const http = require('http')

http.createServer((request, response) => {
  console.log('request', request.url)

  // 允许跨域请求  写返回的状态
  response.writeHead(200, {
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Headers': 'X-Test-Cors',  //允许自定义的头
    'Access-Control-Allow-Methods': 'PUT, POST, GET',
    'Access-Control-Max-Age': '1000', //1000ms内不用再次发送预请求
  })

  response.end('123')
}).listen(8887)

console.log('server listening on 8887')

Access-Control-Max-Age 这个响应首部表示 preflight request  (预检请求)的返回结果(即 Access-Control-Allow-Methods 和Access-Control-Allow-Headers 提供的信息) 可以被缓存多久。

9.  缓存Cache-Control: (哈希值用于刷新浏览器缓存)

可缓存性
public任何地方都可以对返回的内容缓存
private只有发起请求的地方可以
no-cache通过服务器端验证后才能使用本地缓存
到期
max-age=<seconds>

缓存还有多过期。      可以将max-age设置为0,

从而让每次访问时缓存都进行刷新。

max-stale=<seconds>可以使用多久的过期缓存
重新验证
must-revalidata如果要提供过期的数据给客户端,则必须向服务器验证数据的新鲜度

缓存验证:

缓存验证
Last-Modified'123'  标记此文件在服务器端最后被修改的时间
Etag'777'   用于标示URL对象是否改变

no-store: 本地和代理服务器都忽略缓存,直接请求数据,下一次请求是200。

no-catch:通过服务器端验证后才能使用本地缓存,下一次请求是304。

使用:

  •  max-age: 缓存时间
 if (request.url === '/script.js') {
    response.writeHead(200, {
      'Content-Type': 'text/javascript',
      'Cache-Control': 'max-age=20',// 客户端缓存,20s内不会重新请求服务端获取资源
    })
    response.end('console.log("script loaded")')
  }

问题:会导致在缓存时间内无法及时更新到客户端

解决方案:通常在实际生产中会将max-age设置比较长(一年),在项目构建的时候,会在将打包的资源加上哈希码(内容有变化,则哈希码也发生变化),那么客户端发起的请求就是一个新的请求,达到更新缓存的目的。

验证资源能否使用缓存:

  • Last-Modified:上次修改时间,配合If-Modified-Since使用。(对比上一次修改时间,验证资源是否需要更新)

服务端在设置Last-Modified之后,浏览器在下一次请求的时候会在请求头中带上If-Modified-Since。

  if (request.url === '/script.js') {
    // const etag = request.headers['if-none-match']
    response.writeHead(200, {
      'Content-Type': 'text/javascript',
      'Cache-Control': 'max-age=2000000, no-cache',
      'Last-Modified': '123',
      'Etag': '777'
    })
    response.end('console.log("script loaded twice")')
  }
  • Etag:通过数据签名验证,配合If-Match使用。(对比资源的签名判断是否需要缓存)

Etag与Catch-Control的区别:

  1. Catch-Control:max-age=30; 在缓存时间内,直接不发送请求
  2. Etag:发送请求有响应,但不下载响应体。

http1.1中,一个tcp连接最多并发6个http请求(谷歌浏览器中)。

http2 中能够在一个tcp连接中发送多个http请求。

10. Cookie和Session

Cookie:1. 通过Set-Cookie设置   2. 下次请求会自动带上  3.键值对,可以设置多个

属性: 

Cookie属性
max-age和expires设置过期时间
Secure只在https的时候发送
HttpOnly无法通过document.cookie访问,保证用户安全

服务端server.js:

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

http.createServer((request, response) => {  //创建请求
  console.log('request', request.url)

  if (request.url === '/') {
    const html = fs.readFileSync('test.html', 'utf8');  //同步读取html内容
    response.writeHead(200, {
      'Content-Type': 'text/html',
      'Set-Cookie': ['abc=123; max-age=2','id=456'], //可以以数组方式传递多个cookie 前面一个字段的有效时间为两秒
      // 2s后abc=123这个数据就过期,request headers中就不会有这个信息出现
    })
    response.end(html)  //响应内容
  }

}).listen(8888)

console.log('server listening on 8888')

客户端test.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>test</title>
</head>
<body>
  <div>content</div>
  <script src="/script.js">
    console.log(document.cookie)
  </script>
</body>
</html>

11.  数据协商

      客户端请求时会声明希望拿到的数据格式和限制,服务端根据请求头返回不同的数据

客户端请求

Accept

声明想要的数据类型

[主类型]/[子类型] ,如text/html,image/jpg

Accept-Encoding

声明进行传输的编码方式

主要是数据压缩的算法,如gzip, deflate, br

Accept-Language

声明希望返回信息的语言

如zh-CN,zh;q=0.9(q表权重,0~1)

Usrer-Agent

声明浏览器和操作系统的相关信息
服务端返回

Content-Type

声明返回的数据格式,

如'X-Content-Type-Options':'nosniff',可阻止浏览器自行猜测返回数据类型而引发的安全问题。

Content-Encoding

声明返回的编码方式,即数据压缩

Content-Language

声明返回的语言

表单发送到服务器时的三种编码方式:

enctype(编码方式)
application/x-www-form-urlencoded默认的编码方式。但是在用文本的传输和MP3等大型文件的时候,使用这种编码就显得 效率低下。 
multipart/form-data指定传输数据为二进制类型,比如图片、mp3、文件
text/plain纯文体的传输。空格转换为 “+” 加号,但不对特殊字符编码

将表单的enctype(编码方式)定义为"multipart/form-data":适用于上传文件的方式

  <form method="POST" enctype="multipart/form-data">
    <input type="text" name="name">
    <input type="password" name="psd">
    <input type="submit">
  </form>

提交表单之后:能够在浏览器请求头中得到如下信息:

Request Header:

Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryCoZcoYObU8Ubn5U2

boundary后的字符串用于分割表单中的每一个部分。

------WebKitFormBoundaryCoZcoYObU8Ubn5U2
Content-Disposition: form-data; name="name"

8月5
------WebKitFormBoundaryCoZcoYObU8Ubn5U2
Content-Disposition: form-data; name="psd"

sss
------WebKitFormBoundaryCoZcoYObU8Ubn5U2--

控制台中的connection ID 代表TCP连接的ID,可以用来区分是否用的同一个连接。

connection: close, //没有重复利用TCP连接,每次TCP请求发送完就关闭了

(HTTP请求是在TCP连接上发送的,一个TCP连接可以发送多个HTTP请求)

12.   Content Security Policy (内容安全策略)

1.  限制资源获取   2.   报告资源获取越权

CSP 大大增强了网页的安全性。

两种方法启动CSP:

1. 一种是通过 HTTP 头信息的Content-Security-Policy的字段

Content-Security-Policy: script-src 'self'; object-src 'none';

2. 通过网页的<meta>标签。

<meta http-equiv="Content-Security-Policy" content="script-src 'self'; object-src 'none'">

( 脚本:只信任当前域名  <object>标签:不信任任何URL,即不加载任何资源)

只允许通过http,https方式加载src资源:

      'Content-Security-Policy': 'default-src http: https:'

只能根据本域名下的JavaScript内容进行加载:

      'Content-Security-Policy': 'default-src self'

13. nginx设置代理缓存

# 代理缓存: 有一个用户请求成功之后,其他用户都可以直接使用该缓存
# keys_zone:缓存空间(shared memory zone)的名称和大小
proxy_cache_path cache levels=1:2 keys_zone=my_cache:10m;

server {
  listen       80;
  # listen       [::]:80 default_server;
  server_name  test.com;

  # return 302 https://$server_name$request_uri;

  location / {
    proxy_cache my_cache;
    proxy_pass http://127.0.0.1:8888;
    proxy_set_header Host $host;
  }
}

14. nginx缓存验证头信息

  if (request.url === '/data') {
    response.writeHead(200, {
      'Cache-Control': 'max-age=2, s-maxage=20, private',
      'Vary': 'X-Test-Cache' // 验证头信息一样才进行缓存,场景: 判断不同的设备进行不一样的缓存
    })
    wait(2).then(() => response.end('success'))
  }

15. https

加密: 使用公钥加密传输信息(就算信息被截取也无法获取内容),再通过私钥进行解密

16. nginx部署https服务

  1. 生成证书
openssl req -x509 -newkey rsa:2048 -nodes -sha256 -keyout localhost-privkey.pem -out localhost-cert.pem

 mac 电脑不能一路回车下去,空字符会导致一些证书无法正常生成的问题。error, no objects specified in config file

2. nginx 配置

路径: /usr/local/etc/nginx/nginx.conf

server {
       # https默认使用端口 ,开启https加密算法ssl
       listen       443 ssl; 
       server_name  test.com;

       ssl_certificate_key  ./certs/localhost-privkey.pem;
       ssl_certificate      ./certs/localhost-cert.pem;

       location / {
           proxy_pass   http://127.0.0.1:8888;
       }

}

3. hosts配置

路径:/etc/hosts

127.0.0.1 localhost
127.0.0.1 test.com

访问:https://test.com,会提示不是安全的链接,就证明配置成功(因为浏览器所需要的https证书要经过认证的,而不是本地直接生成使用)。

  • 配置http的情况下直接跳转https。server_name即test.com,request_uri即访问的url
server {
    listen 80;
    listen [::]:80 default_server;
    server_name test.com;
    return 302 https://$server_name$request_uri;
}

17. http2

  • HTTP/1.1
    • 纯文本形式的报文
    • 引入了持久链接,即TCP默认不关闭,可以被多个请求复用
    • 引入pipeline管道机制,一个TCP连接,可以同时发送多个请求
      • 管道化要求服务端必须按照请求发送的顺序返回响应,会导致队头阻塞,可以使用HTTP2的多路复用解决
  • HTTP/2
    • 头部压缩
    • HTTP/2 采用二进制传输数据,协议解析起来更高效
    • 多路复用
      • 分帧传输:​​​​​​在一个tcp连接上并发发送多个请求
    • Server Push 服务器推送
  1. nginx 配置

# 使用http2需要在https的条件下
server {
  listen       443 http2;
  server_name  test.com;

  # server push
  http2_push_preload  on;

  ...
}

     2. 服务端配置

http.createServer(function (request, response) {
    response.writeHead(200, {
      'Content-Type': 'text/html',
      'Connection': 'keep-alive',
      // 绝对路径;图片类型;需要服务端推送
      'Link': '</test.jpg>; as=image; rel=preload'
    })
    response.end(html)
})

3. 终端测试http服务

-k: 忽略证书问题。 使用nginx代理服务器能够自动判断浏览器支持的http类型。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值