美文网首页
HTTP 协议原理(二):总览各种特性

HTTP 协议原理(二):总览各种特性

作者: 林ze宏 | 来源:发表于2021-05-30 15:02 被阅读0次

目录

  • 1 模拟跨域请求
  • 2 CORS 跨域限制以及预请求验证
  • 3 Cache-Control 的含义和使用
  • 4 Last-Modified 和 Etag
  • 5 cookie 和 session
  • 6 HTTP 长连接
  • 7 数据协商
  • 7.1 请求
  • 7.2 返回
  • 8 重定向, 301 和 302

1 模拟跨域请求

curl 命令

curl www.baidu.com

text.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <script>
    /* 向 8887 发送请求 */
    const xhr = new XMLHttpRequest();
    xhr.open('GET', 'http://127.0.0.1:8887');
    xhr.send();  
  </script>

  <!-- jsonp -->
  <!-- <script src="http://127.0.0.1:8887"></script> -->

</body>

</html>

service8.js

/* 读取 text.html,8888 服务 向 8887 服务 跨域请求 */

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

http.createServer(function (request, response) {
  console.log('request', request.url);
  const html = fs.readFileSync('text.html', 'utf-8');
  response.writeHead(200, {
    'Content-Type': 'text-html'
  })
  response.end(html);
}).listen(8888)

console.log('server listing 8888');

service7.js

/* 8887 服务允许跨域 */

const http = require('http');

http.createServer(function (request, response) {
  console.log('request--8887', request.url);

  response.writeHead(200, { // 允许跨域
    'Access-Control-Allow-Origin': 'http://127.0.0.1:8888'
    // 'Access-Control-Allow-Origin': '*'
  })

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

console.log('server listing 8887');

2 CORS 跨域限制以及预请求验证

CORS 跨域默认允许的方法:

  • GET

  • POST

  • HEAD

而 PUT、DELETE 默认不允许跨域请求,需要先发送预请求进行验证。

跨域默认允许的 Content-Type:

  • text/plain

  • multipart/form-data

  • application/x-www-form-urlencoded

其他限制

  • 请求头限制(自定义请求头默认不允许跨域)

Access-Control- 响应头说明

text.html,使用 fetch

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <script>
    /* 向 8887 发送请求 */
    fetch('http://127.0.0.1:8887/', {
      method: 'PUT',
      headers: {
        'X-Test-Cors': '111'
      }
    })
  </script>

</body>

</html>

service7.js,配置其他响应头字段

/* 8887 服务允许跨域 */

const http = require('http');

http.createServer(function (request, response) {
  console.log('request--8887', request.url);

  response.writeHead(200, { // 允许跨域
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Headers': 'X-Test-Cors',
    'Access-Control-Allow-Methods': 'PUT,POST,DELETE,GET,HEAD',
    'Access-Control-Max-Age': '10000'
  })

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

console.log('server listing 8887');


  • Access-Control-Allow-Headers
    允许自定义请求头请求跨域

  • Access-Control-Allow-Headers
    允许方法请求跨域

  • Access-Control-Max-Age
    允许在最大的时间内,浏览器不用再发送预请求

3 Cache-Control 的含义和使用

图示

Cache-Control 是一个客户端缓存,如果服务器的资源发生改变的时候,而客户端的 url 没有改变,不知道服务器资源是否有变化,所以,还是会从客户端缓存里面直接取;

当服务端资源发生改变的时候,浏览器不知道是否改变,常见的解决方案为,在构架打包的时候,会根据资源的内容,在对应的资源后面加一段 hash 码,当下一次的内容发生改变的时候,则,重新构架打包出来的 hash 就会发生改变,客户端就会重新请求改变后的资源了,刷新客户端缓存。

  • 可缓存性
    public:浏览器或者中间代理服务器都可以缓存服务器返回的内容;

    private:只有发起请求的浏览器才能缓存,中间代理服务器不可以缓存;

    no-cache:本地可以缓存,但是需要通过服务器验证,不能缓存;

  • 到期(这个缓存什么时候到期)

    max-age = <seconds>:设置多少秒后过期

    s-maxage = <seconds>:在代理服务器生效,如果在代理服务器同时设置 max-age、s-maxage,则以 s-maxage 为主

    max-stale = <seconds>:了解

  • 重新验证

    must-revalidate:过期之后,必须重新发送请求,不能使用缓存;

    proxy-revalidate:在代理服务器设置,同 must-revalidate 一样;

  • 其他

    no-store:一定不能缓存

    no-transform:了解

实例:

text.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>

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

</body>

</html>

service8.js

/* 读取 text.html,8888 服务 向 8887 服务 跨域请求 */

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

http.createServer(function (request, response) {
  console.log('request', request.url);
  if (request.url === "/") {
    const html = fs.readFileSync('text.html', 'utf-8');
    response.writeHead(200, {
      'Content-Type': 'text-html'
    })
    response.end(html);
  }

  if (request.url === "/srcipt.js") {
    response.writeHead(200, {
      'Content-Type': 'text/javascript',
      'Cache-Control': 'max-age=10, public'
    })
    response.end('console.log("11111111")');
  }


}).listen(8888)

console.log('server listing 8888');

4 Last-Modified 和 Etag

重新验证

  • Last-Modified

    上次修改时间

    配合 If-Modified-Since 或者 If-Unmodified-Since 使用

    对比上次修改时间以验证资源是否需要更新

  • Etag

    数据签名

    配置 If-Match 或者 If-None-Match 使用

    对比资源的签名判断是否使用缓存

实例:
service8.js

/* 读取 text.html,8888 服务 向 8887 服务 跨域请求 */

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

http.createServer(function (request, response) {
  console.log('request', request.url);
  if (request.url === "/") {
    const html = fs.readFileSync('text.html', 'utf-8');
    response.writeHead(200, {
      'Content-Type': 'text-html'
    })
    response.end(html);
  }

  if (request.url === "/srcipt.js") {

    const etag = request.headers['if-none-match']; // 获取客户端的设置的 Etag 签名

    if (etag === '456') {
      response.writeHead(304, { // 直接从缓存取
        'Content-Type': 'text/javascript',
        'Cache-Control': 'max-age=10000, no-cache',
        'Last-Modified': '123',
        'Etag': '456',
      })
      response.end('');
    } else {
      response.writeHead(200, {
        'Content-Type': 'text/javascript',
        'Cache-Control': 'max-age=10000, no-cache',
        'Last-Modified': '123',
        'Etag': '456',
      })
      response.end('console.log("11111111")');
    }
  }


}).listen(8888)

console.log('server listing 8888');

第一次请求 后面请求

5 cookie 和 session

cookie

  • 通过 Set-Cookie 设置

  • 下次请求会自动带上

  • 键值对,可以设置多个

cookie 属性

  • max-age 和 expires 设置过期时间

  • Secure 只在 https 的时候发送

  • HttpOnly 无法通过document.cookie 访问

实例
text.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <script>
    console.log(document.cookie)
  </script>

  <h1>content</h1>

</body>

</html>

service8.js

/* 读取 text.html,8888 服务 向 8887 服务 跨域请求 */

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

http.createServer(function (request, response) {
  console.log('request', request.url);
  if (request.url === "test.com") {
    const html = fs.readFileSync('text.html', 'utf-8');
    response.writeHead(200, {
      'Content-Type': 'text-html',
      'Set-cookie': ['id=123; max-age=5', 'age=12; HttpOnly; domain=test.com']
    })
    response.end(html);
  }

}).listen(8888)

console.log('server listing 8888');

说明:

  • 通过 Set-cookie 设置 cookie;

  • cookie 可以设置多个;

  • max-age 设置该 cookie 最长过期时间,单位秒;

  • HttpOnly 无法通过document.cookie 访问,安全性;

  • domain 设置二级域名相同的不同域可以共享 cookie;

6 HTTP 长连接

HTTP 长连接,通过设置:keep-alive

Connection: 'keep-alive'

Http 请求,是在 TCP 连接的基础之上,而使用 HTTP 长连接,可以减少 TCP 连接的建立(三次握手),提高请求速度;

7 数据协商

分类

  • 请求

  • 返回

7.1 请求

  • Accept:声明客户端想要的数据类型

  • Accept-Encoding:声明客户端想要类型的编码,一般指可以接受服务端返回的压缩格式,如:gzip, deflate, br

  • Accept-Language:声明客户端可以接受的语言;

  • User-Agnet:表示浏览器和系统的相关信息,移动端的浏览器跟 PC 端的浏览器是不同的,可以根据 User-Agnet,进行判断,要返回的是移动端的页面还是 PC 端的页面

说明:User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36

Mozilla/5.0:最开始浏览器是由网景公司开发的;

(Windows NT 10.0; WOW64) :说明我的系统是 window 10,64位;

AppleWebKit/537.36:WebKit 内核,是由苹果开发的,所以必须带上;

Chrome/75.0.3770.142:Chrome 和对应的版本号;

Safari/537.36:WebKit 内核,是由苹果开发的,所以会带上 Safari 信息;

7.2 返回

  • Content-Type:对应 Accept,选择其中的一种作为返回格式,也就是服务端实际返回的数据格式

  • Content-Encoding:对应 Accept-Encoding,说明服务端具体是用什么压缩格式

  • Content-Language:对应 Accept-Language,说明是否是根据客户端的要求,返回想要的语言;

实例

/* 读取 text.html,8888 服务 向 8887 服务 跨域请求 */

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

http.createServer(function (request, response) {
  console.log('request', request.url);
  const html = fs.readFileSync('text.html');
  response.writeHead(200, {
    'Content-Type': 'text-html',
    'Content-Encoding': 'gzip'
  })
  response.end(zlib.gzipSync(html));

}).listen(8888)

console.log('server listing 8888');

8 重定向, 301 和 302

301:重定向,永久性跳转,也就是通过访问 '/',确定永远都指向了 '/new';慎重!!!因为如果后面反悔了,即使服务端修改了,但是,浏览器还是会缓存之前的 301 后的地址,除非客户手动的清除数据,否则,永远都不会改变,不可控。

302:重定向,临时跳转,有可能以后,不是跳转到 '/new' 路径;

/* 读取 text.html,8888 服务 向 8887 服务 跨域请求 */

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

http.createServer(function (request, response) {
  console.log('request', request.url);
  if (request.url === '/') {
    response.writeHead(302, { // 重定向,临时跳转,有可能以后,不是跳转到 '/new' 路径
      'Location': '/new'
    })
    response.end();
  }

  // if (request.url === '/') {
  // 重定向,永久性跳转,也就是通过访问 '/',确定永远都指向了 '/new';慎重!!!
  // 因为如果后面反悔了,即使服务端修改了,但是,浏览器还是会缓存之前的 301 后的地址,除非客户手动的清除数据,否则,永远都不会改变,不可控。
  //   response.writeHead(301, {
  //     'Location': '/new'
  //   })
  //   response.end();
  // }

  if (request.url === '/new') {
    const html = fs.readFileSync('text.html', 'utf-8');
    response.writeHead(200, {
      'Content-Type': 'text-html',
    })
    response.end('this is Content');
  }

}).listen(8888)

console.log('server listing 8888');

相关文章

网友评论

      本文标题:HTTP 协议原理(二):总览各种特性

      本文链接:https://www.haomeiwen.com/subject/bjullctx.html