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

目录

  • 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');

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容