【Nginx23】Nginx学习:响应头与Map变量操作

news2024/11/27 12:37:33

Nginx学习:响应头与Map变量操作

响应头是非常重要的内容,浏览器或者客户端有很多东西可能都是根据响应头来进行判断操作的,比如说最典型的 Content-Type ,之前我们也演示过,直接设置一个空的 types 然后指定默认的数据类型的值,所有的请求浏览器都会直接下载。另外,我们现在在做前后分离的开发时,也经常会通过头信息来传递一些标志参数,那么自定义响应头的作用就更加重要了。另外一个 Map 部分则是 Nginx 中的一种变量设置方式,话不多说,直接开始吧。

今天学习的内容响应头部分都是可以设置在 http、server、location 中的,有特殊情况的我会单独说。而 Map 部分则都是只能在 http 中进行配置。

响应头

在 Nginx 中,响应头模块就是 ngx_http_headers_module 模块。总共就三个配置指令,其实并不复杂。而且相信其中两个指令大家都至少是见过的。除了可以添加自定义的响应头之外,在这个模块中还有一个非常重要的内容就是 HTTP 的 Expire 缓存设置。在最后,我们将会统一进行一个测试,先来看看响应头模块中的三个配置指令。

add_header

如果响应代码等于 200、201 (1.3.10)、204、206、301、302、303、304、307 (1.1.16、1.0.13) 或 308 (1.13),则将指定字段添加到响应标头。

add_header name value [always];

默认值没有,但是 Nginx 会默认帮我们添加一些响应头,比如说 Server 显示 Nginx 版本号的,还有 Content-Type 这个标准响应头。它的参数值可以包含变量,最后的 always 表示忽略上面的那些状态码,任何响应都返回这个响应头。

我们可以定义多个响应头,如果当前的作用域中没有定义,那么会从上一级继承。

如果是空的内容,这个响应头不会返回。

add_trailer

如果响应代码等于 200、201、206、301、302、303、307 或 308,则将指定字段添加到响应的末尾。

add_trailer name value [always];

它的用法和 add_header 是一样的,但是不好测,据说是用在分段响应上的。不过我们之前在 Nginx学习:HTTP核心模块(十二)内嵌变量https://mp.weixin.qq.com/s/0ks7GgfcvJpQp7mA1IgQcA 中讲过一个 $sent_trailer_[name] 变量,大家还记得吧?它可以获取到响应尾所添加的内容,然后我们就可以输出到日志中。当时已经做过测试啦,这里就不再重复说了。

expires

如果响应代码等于 200、201 (1.3.10)、204、206、301、302、303、304、307 (1.1.1),则启用或禁用添加或修改“Expires”和“Cache-Control”响应头字段。

expires [modified] time;
expires epoch | max | off;

默认值是 off ,也就是关闭的,任何响应都不会返回 Expire 和 Cache-Control 响应头。这个呀,其实就是 HTTP 中的 Expire 和 Cache-Control 的基础知识相关的配置。比如我们查看一些网站的请求时,会有一些静态资源像是 js 文件、图片之类的,会返回 200 响应,但是后面还会跟着一个 from memory cache 或者 from disk cache 。这种就是使用了 Expire 或 Cache-Control 缓存,在缓存有效时间之内,都会直接从本地读取缓存,不会发送请求。

和 Last-Modified 以及 Etag 的区别就是,这两个以文件的修改为主,真的会发一个请求到服务器,服务器判断没修改之后再返回 304 。而 Expire 和 Cache-Control 连请求都不会发,必须强制刷新或者让浏览器不使用缓存。而且直接请求 URL 看不到效果,需要是静态页面中通过 src 加载的内容才会走这个缓存。Expire 比较老一些,新的是 Cache-Control ,所以两个同时存在时会走 Cache-Control 。不过 Nginx 中这个配置指令会一起设置。

好了,点到为止,还不太清楚的小伙伴可以继续查阅相关资料哦。

正常来说,这个 time 是要过期的时间长度,比如 10 秒后过期写 10s 就好了。没错,是当前时间加上 expires 设置的时间。如果使用 modified ,则是当前访问路径的文件的修改时间加上 expires 的时间。注意,服务端和客户端的时间要一致,比如我之前测试时,服务端虚拟机的时间比我的电脑慢了3分钟,设置 10s 的缓存就一直都不会生效。

我们也可以通过 @ 符号指定一个时间。

expires @15h30m;

这样就是指定当天的 15 点 30 分过期。

expires 还会影响到 Cache-Control 的值。

  • 如果设置一个负数的话,Cache-Control 会设置 no-cache ;

  • 如果设置为非负数,包括 0 的话,Cache-Control 的 max-age 会等于这个数值;

而真正的 Expire 响应头,则是具体的 GMT 时间值,也就是当前时间加上 expires 指定后的具体时间。

设置为 epoch 参数,则表示永远不缓存,对应的头信息为 “Expires” 设置成 “Thu, 01 Jan 1970 00:00:01 GMT” 而 “Cache-Control” 会设置成 “no-cache” ;设置为 max 参数则表示永远不过期,“Expires” 设置成 “Thu, 31 Dec 2037 23:55:55 GMT” 而 “Cache-Control” 会设置成 10 年。

最后一个参数的值,可以是一个变量。

响应头测试

好了,就这三个配置指令,不多吧。但是,如你对 HTTP 的基础知识真的都不清楚的话,那就没别的办法了,先自己测试一下,明白是什么意思,然后赶紧去恶补一下吧。

我们先写个 location 方便测试。

location /headers/ {
 alias html/;

  add_header PPOP abc$uri;
  add_header GET_VALUE $arg_a;
  
  add_trailer op def$uri;
  access_log logs/params2.log vvv;

  expires 10s;
  add_header Cache-Control public;
}

通过 alias 还是指向了 html 这个根目录,主要是我比较懒,不想多建目录啦。然后 add_header 的大家自己测试一下吧,看看响应头会不会返回数据。注意第二个,我们是接收的 $arg_[name] 这种形式的变量参数哦,如果不传变量看看会不会有响应头返回回来。

然后就是 add_trailer 的测试,上回我们只是大概说了下,这回还是再简单的看一下。在 location 中,我们将访问日志 access_log 配置为一个新的日志目录文件了,并且指定了日志格式是 vvv 。然后我们需要再到 http 中添加一个配置。

// http 下
log_format vvv op_trailer=$sent_trailer_op;

这个配置指令后面我们学习日志模块时会详细地再学习,现在先这么配就好了。然后访问请求之后,就可以在日志文件中看到信息了。

// params2.log
………………
op_trailer=def/headers/index.html
………………

好了,最后的重点,就是对于 expires 的测试了。我们需要先创建一个静态文件,然后加载一张图片。注意,图片路径我也是走的上面配置的 headers 这个 location ,直接走 /img/ 目录是不行的哦,因为我们的 expires 是配置在这个 location 当中了。

// cache1.html
222111
<img src="/headers/img/1.jpeg" width="200px"/>

然后开始请求访问,并多次刷新。我们测试的 10s ,需要注意测试机与当前主机的时间同步问题。另外,还添加了一个 Cache-Control 头设置为 public ,这个有啥用大家也可以自己查下哦,都是基础知识。不用设置它也可以。

489dbade732064ec7da0d691e8dc14a2.png

注意看,第一次是 200 正常响应,然后中间几次也是 200 ,但后面有了一个 memory cache 的标志了。查看 Nginx 的 access_log ,也不会看到这些请求,说明真的是没有发请求。然后 10s 后,再请求一次,会发现返回了一个 304 ,这是 Last-Modified 在起作用。同时,Expire 也被更新了。之后的请求又开始 memory cache 了。

看到了吧,这就是静态资源的多级缓存。在架构设计中,缓存前推中最重要的就是 HTTP 的这两块缓存,是非常重要的理论知识,而且也是非常容易就通过配置能够实现的理论实践,大家可以赶紧应用在自己的项目中哦。好处嘛,减少流量带宽占用,毕竟现在流量费也挺贵的,好吧,你不担心流量费,但至少 access_log 文件还能小点是不是。

ps.去看看京东、淘宝、网易、新浪这些大网站是怎么设置过期时间的哦,大部分图片可能都是 max ,而 js、css 之类的则可能会比较短哦。

Map变量

之前我们学过的都是 Nginx 提供的系统变量,这一次,我们要自己设置变量啦。在 Nginx 中,目前可知的设置变量的方法有三种,分别是 set 指令、map 指令和正则方式。正则就是匹配之后那个 $1 这种。

set 指令我们后面再说,今天先来看看 map 模块相关的指令。

map

Map 模块 ngx_http_map_module ,它可以创建变量,但是,它的值是取决于另外一个变量的。什么意思呢?我们先来看看这个指令的介绍。

map string $variable { ... }

这参数有点怪呀,第一个 string 表明要进行判断的值。第二个参数就是我们要创建的变量名称。后面花括号中的内容是对于那个 string 的匹配结果。来看一个例子。

map $arg_a $a {
   default 0;
   aaa 1;
   ~.*aaa 2;
   aaa* 3;
   bbb 1;
   ccc 2;
}

server {
  listen 8088;
  root html;

  location / {
    if ($a = 1) {
     return 200 aaa$a;
    }
    if ($a = 2) {
     return 200 bbb$a;
    }
  return 200 $a;
}

注意,map 要放在 http 下面哦,不能在 server 或 location 中。

在 map 中,我们设置了第一个参数是 $arg_[name] 这个变量,这样我们就可以通过 GET 参数 a 来传递值。第二个参数是赋值之后的变量名。

花括号中的内容是匹配规则,可以看到 default 表示默认值,aaa 是普通匹配,~.*aaa 是正则匹配。意思就是,请求中有一个 GET 参数是 a ,并且参数的值是 aaa ,那么 $a 的结果就是 1 ;如果是 xaaa ,那么 $a 就是 2 ;如果是 aaa* 结果值就是 3 ,注意,这个 * 没有特别含义的,目前状态下是不能进行通配的;其它两个不用说了吧;如果不匹配,或者没有这个 GET 参数的话,返回 0 。

然后在下面的 location 中,如果 $a 的值是 1 ,那么返回的结果前面加上 aaa ,如果是 2,结果前面加上 bbb ,其它情况直接返回 $a 的值。

来测试一下吧。

[root@localhost ~]# curl http://127.0.0.1:8088/
0
[root@localhost ~]# curl http://127.0.0.1:8088/?a=aaa
aaa1
[root@localhost ~]# curl http://127.0.0.1:8088/?a=waaa
bbb2
[root@localhost ~]# curl http://127.0.0.1:8088/?a=ccc
bbb2
[root@localhost ~]# curl http://127.0.0.1:8088/?a=ddd
0

看出效果了吧,是不是感觉似曾相识?没错,不要怀疑自己,这就是编程语言中的 switch 。

第一个参数是一个 string ,你也可以写一个固定的字符串,但是那样就没意义了。因此,map 通常都会配合系统提供的变量来进行操作,比如官网的例子。

map $http_host $name {
    hostnames;

    default       0;

    example.com   1;
    *.example.com 1;
    example.org   2;
    *.example.org 2;
    .example.net  3;
    wap.*         4;
}

map $http_user_agent $mobile {
    default       0;
    "~Opera Mini" 1;
}

第一个例子是对 Host 请求头进行匹配,返回 $name 值。注意,这里的 * 是可以通配的,因为这是针对主机名的匹配,其实走的是主机掩码,就是域名那一套,比如泛解析的掩码通配。可以加上一个 hostnames 参数,就可以实现对主机名的通配,这个 hostnames 需要放在最上面。

第二个例子可以用于判断浏览器类型,比如说现在最常用的判断是否移动端,或者判断是否是微信客户端,然后通过这个变量就可以配合 if 指令进行跳转,高大上吧!

花括号中,除了匹配规则、default 和 hostnames 之外 ,还有两个特殊的参数,include 和 volatile ,前者可以包含一个带有值的文件。可以有多个。后者可以表示该变量不可缓存。

另外,如果正则、hostnames、还有普通匹配同时匹配到了怎么办呢?那就是优先顺序的问题了嘛。

  • 普通字符串值最高

  • 前面带 * 通配掩码的,比如:*.example.com

  • 后面带 * 通配掩码的,比如:mail.*

  • 第一个匹配的正则表达式(在配置文件中的出现顺序)

  • 默认 default 的值

map_hash_bucket_size

设置映射变量哈希表的存储桶大小。默认值取决于处理器的缓存线大小。

map_hash_bucket_size size;

默认值根据系统情况而定,默认值是 32 或 64 或 128 。

map_hash_max_size

设置映射变量哈希表的最大大小。

map_hash_max_size size;

默认值是 2048。

设置哈希表

之前很多内容中其实都提到过哈希表这个东西,今天就放到这里一起说明一下吧,因为 Map 模块后面的两个配置指令也和这个东西有关,以下是官方文档的解释。

为了快速处理静态的数据集合,诸如虚拟主机名、 map指令的值、 MIME类型和请求头的字段名,Nginx 使用了哈希表。在 Nginx 启动和更新配置的过程中,它会尽可能为哈希表选择最小的容量, 同时使每个哈希桶的长度不超过设置的配置参数。这些桶用于保存键和对应的哈希值。整个哈希表的容量以哈希桶的数量来定义。Nginx不断调整哈希表直到哈希表容量超过配置的最大值。大部分哈希表都有对应的指令,允许修改这些配置参数。比如,针对虚拟主机名的哈希表,有server_names_hash_max_size 和 server_names_hash_bucket_size 两条指令。

哈希桶大小的参数会对齐到处理器缓存线长度的整数倍。这将加速哈希表中的键查找,因为在现代的处理器上,这可以减少内存访问的次数。如果哈希桶大小等于处理器的缓存线长度,那么在最坏情况下,键查找时的内存访问次数是两次—— 第一次是计算哈希桶的地址,第二次是在哈希桶内进行键查找。因此,如果nginx提示需要增大哈希表容量或者哈希桶大小时,应优先增大前者。

说实话,我也不懂是啥意思,但看得出来:

  • 一是数据结构方面的问题,哈希是空间换时间的一种策略,因此,占用的内存空间也不能无限大,会有一个限制

  • 二是哈希表在 Nginx 启动时就把所有键值对确定了,之后不能再添加修改(开放地址法,键的数量大于可能的值的数量,不需要进行线性探测),而且尽量选择最小值,但是会通过哈希桶的数量来调整容量直到达到最大值

  • 三是有计算机原理中内存对齐的概念,哈希表可以快速访问,通过对齐能够减少内存访问次数(CPU缓存)

  • 四是如果 Nginx 日志中提示需要增大哈希表的话,优先调整 xxxx_bucket_size 之类的指令大小,也就是增大容量

其它的嘛?哥们实在是无能为力了 ,只能帮到这里了。希望各位大佬有时间并且不小心看到这篇文章的话,能够不吝赐教。

总结

今天的内容中,add_header 确实是用过,但是其它的,说实话,真的从来没接触过。没错,你没看错,干了这么些年,直到现在我也没完全搞清楚 HTTP 中缓存的这些东西。但是,通过学习今天的内容,并且在写文章时不断地查阅资料,这下真的算是彻底搞明白了 Expire 和 Last-Modified 这些东西到底是干嘛了。这下面试的时候总算不慌了,当然是前提别人能给 35+ 快 40 的老码农一个能面试的机会。Cry....

另外的 Map 模块,其实也从来都没用过,甚至之前都不知道有这个功能。毕竟在 Nginx 中,如果需要定义变量的话,set 指令真的很方便,不过通过了今天的学习,貌似 map 还是一个可以挖掘的宝藏功能哦,而且它真的非常像 switch 的作用,更加地灵活方便。

参考文档:

http://nginx.org/en/docs/http/ngx_http_headers_module.html

http://nginx.org/en/docs/http/ngx_http_map_module.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/978138.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OPC UA Tunnel提高了OPC Classic通信的安全性

2023年8月22日&#xff0c;Softing工业自动化推出了dataFEED OPC Suite 5.30版本。该版本增加了两项新功能&#xff1a;OPC UA Tunnel和InfluxDB数据库连接。 &#xff08;OPC UA Tunnel提高了OPC Classic通信的安全性&#xff09; | OPC UA Tunnel——用于提高OPC Classic通信…

日志框架Slf4j作用及其实现原理

目录 1 设计模式门面模式2 slf4j源码解析 1 设计模式门面模式 设计模式之门面模式与装饰器模式详解和应用&#xff1a;https://blog.csdn.net/ZGL_cyy/article/details/129073521 slf4j是门面模式的典型应用&#xff0c;因此在讲slf4j前&#xff0c;我们先简单回顾一下门面模…

前端日期比较大小(超简单版,不需要转换时间戳)

思路&#xff08;把日期转换为Number类型进行比较&#xff09; 效果如图&#xff1a; 第一步&#xff1a;如果获取到的日期是 &#xff1a;"2023-08-03 00:00:00" 用 timesss.split( )[0] // .split( ) 中间有个空格哦 timesss是自己数据的变…

nlp系列(7)实体识别(Bert)pytorch

模型介绍 本项目是使用Bert模型来进行文本的实体识别。 Bert模型介绍可以查看这篇文章&#xff1a;nlp系列&#xff08;2&#xff09;文本分类&#xff08;Bert&#xff09;pytorch_bert文本分类_牧子川的博客-CSDN博客 模型结构 Bert模型的模型结构&#xff1a; 数据介绍 …

解决Android U无法通过adb安装应用(Caller has no access to session -1)的问题

在Android U&#xff08;14&#xff09;上&#xff0c;对通过adb安装应用做了限制。默认的情况下&#xff0c;当执行以下命令的时候 adb install XXX.apk会提示执行异常 Performing Streamed Install adb: failed to install XXX.apk: Exception occurred while executing in…

java面试之ThreadLocal问题

什么是ThreadLocal,它的基本用法是什么 简单来说就是能在多线程中保持变量独立的线程对象 不用Threadlocal多线程访问同一个变量会出现的问题 package com.pxx;/*** Created by Administrator on 2023/9/3.*/ public class Demo1 {private String v1;public String getV1() …

群晖 DS918通过CISCO SG250 LACP 链路聚合效果不佳的问题解决

问题表现 使用的是CISCO交换机打开LACP 链路聚合&#xff0c;且DS918上完成接口聚合并配置为平衡TCP模式后。通过IPREF测速整体网络性能仅能达到300Mbps左右。 问题解决 检查CISCO交换机LAG配置中&#xff0c;针对DS918的接口组是否正确配置了流量配置。请按照如下图所示&#…

易云维®医院后勤管理系统软件利用物联网智能网关帮助实现医院设备实现智能化、信息化管理

近年来&#xff0c;我国医院逐渐意识到医院设备信息化管理的重要性&#xff0c;逐步建立医院后勤管理系统软件&#xff0c;以提高信息化管理水平。该系统是利用数据库技术&#xff0c;为医院的中央空调、洁净空调、电梯、锅炉、医疗设备等建立电子档案&#xff0c;把设备监控、…

Python中的PYTHONPATH

迷途小书童 读完需要 4分钟 速读仅需 2 分钟 大家好&#xff0c;我是迷途小书童&#xff01; 今天来聊聊 PYTHONPATH。 PYTHONPATH 是一个环境变量&#xff0c;它是一个列表&#xff0c;列表的元素是目录&#xff0c;也就是一些文件夹的路径&#xff0c;它告诉 Python 解释器去…

《自然的艺术形态》

艺术是科学的最高形式。《自然的艺术形态》是恩斯特海克尔在19世纪博物学和生物学的最高峰对自然界所作出的最美阐释。透过自然科学巨匠的慧眼&#xff0c;人类能多一个视角&#xff0c;认识栩栩如生的自然万物&#xff0c;其奇美&#xff0c;其壮观&#xff0c;若非建立在自然…

vs+opencv+QT调试程序

2021-09-28vsopencvQT简单的图像处理工程_opencv 用qt还是vs_二两山栀子的博客-CSDN博客 【vsopencvQt搭建简单的图像处理界面】https://www.bilibili.com/video/BV16T411j7XQ?vd_source0aeb782d0b9c2e6b0e0cdea3e2121eba 调试过程一直出现这种问题&#xff0c;后来改DEBUG为…

HDLBits 练习 Always if2 并给出逻辑简化过程

题目 Always if2 在前面的练习中我们使用了简单的逻辑门与一些逻辑门的组合。这些电路都可以作为组合电路的例子。 组合意味着这个电路的输出只是输入的函数&#xff08;数学意义上的&#xff09;。数学上的函数就意味着当你给定一个输入的时候 对应的只会有一个输出。因此有一…

ChatPaper临时升级教程

ChatPaper临时升级教程 文章目录 ChatPaper临时升级教程必要的声明&#xff1a;升级教程&#xff1a; 必要的声明&#xff1a; 最近只能手动发卡了&#xff0c;所以单独写一个手动升级的教程。 先声明一下付费的内容&#xff1a; 500K大概是30篇左右的总结&#xff1b; 200k大…

计算机网络的故事——HTTP首部

HTTP首部 在HTTP协议通信交互中使用的首部字段。不限于RFC2616中定义的47种首部字段&#xff0c;还有Cookie、setCookie和Content-Disposition等 HTTP 首部字段将定义成缓存代理和非缓存代理的行为&#xff0c;分成 2 种类型。端到端首部和逐跳首部

单向链表(c/c++)

链表是一种常见的数据结构&#xff0c;其中运用到了结构体指针&#xff0c;链表可以实现动态存储分配&#xff0c;换而言之&#xff0c;链表是一个功能强大的数组&#xff0c;可以在某个节点定义多种数据类型&#xff0c;可以实现任意的添加&#xff0c;删除&#xff0c;插入节…

通过nginx将https协议反向代理到http协议请求上

通过nginx将https协议反向代理到http协议请求上 1、问题背景2、介绍nginx的反向代理功能及配置https协议3、具体实现3.1 后端服务支持方式3.2 nginx重定向方式 3.3、nginx的反向代理方式4、关于nginx常用模块和指令 1、问题背景 目前一个系统仅支持https协议访问&#xff0c;因…

anaconda navigator打不开,一直在loading画面

anaconda navigator打不开&#xff0c;一直在loading画面。百度解决方法&#xff0c;用网上的方法在命令窗口里运行conda update anaconda结果一直显示 solving environment卡在那里。又尝试用管理员身份运行还是不行&#xff0c;打开后出现There in aninstance of Anaconda Na…

在MySQL中查看数据库和表的数据大小

在MySQL中查看数据库和表的数据大小 在管理和维护MySQL数据库时&#xff0c;了解数据库和表的数据大小是非常重要的。这可以帮助您监控数据库的增长、优化性能以及规划存储需求。本博客将介绍如何使用SQL查询来查看MySQL数据库和表的数据大小。 查看MySQL数据库的总数据大小 …

linux并发服务器 —— IO多路复用(八)

半关闭、端口复用 半关闭只能实现数据单方向的传输&#xff1b;当TCP 接中A向 B 发送 FIN 请求关闭&#xff0c;另一端 B 回应ACK 之后 (A 端进入 FIN_WAIT_2 状态)&#xff0c;并没有立即发送 FIN 给 A&#xff0c;A 方处于半连接状态 (半开关)&#xff0c;此时 A 可以接收 B…

vscode使用delve调试golang程序

环境配置 delve仓库&#xff0c;含有教程&#xff1a;https://github.com/go-delve/delve golang的debugging教程&#xff1a;https://github.com/golang/vscode-go/wiki/debugging > go version go version go1.20 windows/amd64> go install github.com/go-delve/de…