CodeAshen's blog CodeAshen's blog
首页
  • Spring Framework

    • 《剖析Spring5核心原理》
    • 《Spring源码轻松学》
  • Spring Boot

    • Spring Boot 2.0深度实践
  • Spring Cloud

    • Spring Cloud
    • Spring Cloud Alibaba
  • RabbitMQ
  • RocketMQ
  • Kafka
  • MySQL8.0详解
  • Redis从入门到高可用
  • Elastic Stack
  • 操作系统
  • 计算机网络
  • 数据结构与算法
  • 云原生
  • Devops
  • 前端
  • 实用工具
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
  • Reference
GitHub (opens new window)

CodeAshen

后端界的小学生
首页
  • Spring Framework

    • 《剖析Spring5核心原理》
    • 《Spring源码轻松学》
  • Spring Boot

    • Spring Boot 2.0深度实践
  • Spring Cloud

    • Spring Cloud
    • Spring Cloud Alibaba
  • RabbitMQ
  • RocketMQ
  • Kafka
  • MySQL8.0详解
  • Redis从入门到高可用
  • Elastic Stack
  • 操作系统
  • 计算机网络
  • 数据结构与算法
  • 云原生
  • Devops
  • 前端
  • 实用工具
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
  • Reference
GitHub (opens new window)
  • RabbitMQ

  • RocketMQ

  • Kafka

  • Nginx

    • 第01章-基础篇
    • 第02章-场景实践篇
    • 第03章-深度学习篇
      • 3.1 动静分离
      • 3.2 Rewrite规则
      • 3.3 高级模块
        • 3.3.1 securelinkmodule模块
        • 3.3.2 ngxhttpgeoip_module模块
      • 3.4 基于Nginx的HTTPS服务
        • 3.4.1 HTTPS介绍
        • 3.4.2 生成证书
        • 3.4.3 nginx配置HTTPS
        • 3.4.4 HTTPS服务优化
      • 3.5 Nginx与Lua开发
        • 3.5.1 Lua基础语法
        • 3.5.2 Nginx+Lua环境
        • 3.5.3 Nginx调用Lua
        • 3.5.4 Nginx+Lua示例
        • 简单示例
        • 灰度发布示例
    • 第04章-架构篇
  • 中间件
  • Nginx
CodeAshen
2023-02-10
目录

第03章-深度学习篇

# 3.1 动静分离

通过中间件将动态请求和静态请求分离。

**好处:**分离资源,减少不必要的请求消耗,减少请求延时。

image-20210105142105753

upstream {
	server 127.0.0.1:8080;
}

server {
	listen		80;
	server_name	localhost;
	
	root /opt/app/code;

	location ~ \.jsp$ { 
		proxy_pass http://java_api; 
		index index.htm index.htm;
    }
    
    location ~ \.(jpg|png|gif)$ { 
    	expires 1h; 
    	gzip on; 
    }
    
    location / { 
    	index index.html index.htm;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 3.2 Rewrite规则

rewrite介绍

Nginx的rewrite可以实现url重写以及重定向,适用场景如下:

  • URL访问跳转,支持开发设计

    页面跳转、兼容性支持、展示效果等

  • SEO优化

  • 维护

    后台维护、流量转发等

  • 安全

配置语法

Syntax:		rewrite regex replacement [flag];
Default:	—
Context:	server, location, if
1
2
3

如果指定的正则表达式与请求URI匹配,则URI将按照 replacement 字符串中的指定进行更改。该 rewrite 指令在其在配置文件中出现的顺序顺序地执行。可以使用标志终止指令的进一步处理。如果替换字符串以 http://,https:// 或 $scheme 开头,则处理停止,并将重定向返回给客户端。

flag参数:

flag可选值 含义
last 停止rewrite检测,rewrite后继续匹配location配置,相当于请求转发
break 停止rewrite检测,rewrite后不再继续匹配location
redirect 返回302临时重定向,地址栏会显示跳转后的地址(后续还是由服务端返回重定向信息)
permanent 返回301永久重定向,地址栏会显示跳转后的地址(客户端保存重定向信息,不通过服务端直接重定向)

Rewrite规则优先级

  1. 执行server块的rewrite指令
  2. 执行location匹配
  3. 执行选定的location中的rewrite

# 3.3 高级模块

# 3.3.1 secure_link_module模块

该模块用于检查请求的链接,限制未经授权的访问,保护资源。

  • 制定并允许检查请求的链接的真实性以及保护资源免遭未经授权的访问
  • 限制链接生效周期

相关配置

1、secure_link

定义一个带有变量的字符串,从中将提取链接的校验和值和过期时间。

Syntax:		secure_link expression;
Default:	—
Context:	http, server, location
1
2
3

2、secure_link_md5

定义一个表达式,将为其计算MD5哈希值,并将其与请求中传递的值进行比较。

表达式应包含链接(资源)的安全部分和秘密成分。如果链接的生存期有限,则表达式还应包含*$secure_link_expires*。

Syntax:		secure_link_md5 expression;
Default:	—
Context:	http, server, location
1
2
3

验证图示:

image-20210105160406648

返回给客户端的下载连接:

image-20210105160520391

客户端使用下载连接发起下载请求后,nginx会进行加密验证和过期验证,校验md5参数的加密信息,加密信息可基于IP等信息生成,校验expires指定的过期时间。

配置示例

location / {
	# 提取链接中的加密串和过期时间
	secure_link $arg_nd5,$arg_expires; 
	# 使用按规则加入字符串"lucifer"进行加密,与上面取到的参数对比,看是否匹配
	secure_link_md5 "$secure_link_expires$uri lucifer";
	
	# 变量$secure_link用于存放验证结果,根据结果执行以下逻辑
	if ($secure_link="") { 
		return 403;
    }
    
    if ($secure_link="0") { 
		return 410;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 3.3.2 ngx_http_geoip_module模块

基于IP地址匹配MaxMind GeoIP二进制文件,读取IP所在地域信息。

# 安装模块
yum install nginx-module-geoip
1
2

适用场景:

  • 区别国内外作HTTP访问规则
  • 区别国内城市地域作HTTP访问规则

相关变量

$geoip_country_name		国家名
$geoip_country_code		国家代码(CN,US)
$geoip_city				城市名
......
1
2
3
4

配置示例

location / {
	# 国家码不是中国就返回403
	if ($geoip_country_code != CN) {
		return 403;
	}
	root /usr/share/nginx/html;
	index index.html index.htm;
}

location /my_ip {
	default_type text/plain; 
	# 输出ip、国家名、国家码、城市名
	return 200 "$remote_addr $geoip_country_name $geoip_country_code $geoip_city";
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 3.4 基于Nginx的HTTPS服务

# 3.4.1 HTTPS介绍

为什么需要HTTPS?因为HTTP不安全?

  1. 传输数据被中间人盗用、信息泄露
  2. 数据内容劫持、篡改

HTTPS协议的实现:对传输内容进行加密以及身份验证

对称加密和非对称加密

对称加密

非对称加密

程参考:Https原理及流程 (opens new window)

# 3.4.2 生成证书

使用 openssl 生成证书请求文件,交给签名机构进行证书签名,这里我们本地签名。

mkdir ssl_key && cd ssl_key
# 用idea算法,生成mykey.key文件,加密位数1024,执行后需要指定密码,记住这个密码
openssl genrsa -idea -out mykey.key 1024
# 生成证书签名请求文件,执行期间需要填写一些信息
openssl req -new -key mykey.key -out mykey.csr
# 至此会生成两个文件,mykey.key和key.csr,发给签名机构进行签名即可
# 本地调试,自己进行签名,生成签名文件mykey.crt
openssl x509 -req -days 3650 -in mykey.csr -signkey mykey.key -out mykey.crt
1
2
3
4
5
6
7
8

image-20210803153205366

# 3.4.3 nginx配置HTTPS

server {
    listen 443;   #HTTPS监听443端口
    server_name 10.60.131.23;
    ssl on;       #开启https
    #指定签名文件和key文件位置
    ssl_certificate /etc/nginx/ssl_key/mykey.crt;
    ssl_certificate_key /etc/nginx/ssl_key/mykey.key;
    
    index index.html index.htm;
    location / {
        root /opt/app/code;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

此时重启nginx,需要输入生成key文件时的密码,重启后就可以通过浏览器使用HTTPS协议请求nginx了。

如今苹果对安全要求越来越高,苹果要求的证书需要符合以下条件:

  • 服务器所有的连接使用TLS1.2以上版本(openssl 1.0.2)
  • HTTPS证书必须使用SHA256以土哈希算法签名
  • HTTPS证书必须使用RSA2048位或ECC256位以上公钥算法d、使用前向加密技术
# 查看openssl版本
openssl version
# 查看加密证书算法类型和加密位数
openssl x509 -noout -text -in ./mykey.crt

# 删除原来crt文件
rm mykey.crt
# 直接通过key文件生成签名文件,符合苹果要求
openssl req -days 36500 -x059 -sha256 -nodes -newkey rsa:2048 -keyout mykey.key -out mykey_apple.crt
1
2
3
4
5
6
7
8
9

# 3.4.4 HTTPS服务优化

  1. 激活keepalive长连接

  2. 设置ssl session缓存

    ssl on;
    ssl_session_cache   shared:SSL:10m;  #配置10MB会话缓存,大约可缓存8000-10000个会话
    ssl_session_timeout 10m;  #会话过期时间10min
    
    1
    2
    3

# 3.5 Nginx与Lua开发

Lua是一个简洁、轻量、可扩展的脚本语言。

Nginx+Lua优势:充分的结合Nginx的并发处理epoll优势和Lua的轻量实现简单的功能切高并发的场景。

# 3.5.1 Lua基础语法

安装

yum install lua
1

运行(分为命令行和脚本文件形式)

# lua
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
> print("Hello, world")
Hello, world
1
2
3
4
# lua ./test.lua
Hello, world
1
2

基本语法:

  • 布尔型:只有 nil 和 false 是 false;0 和空字符串等其他的都是 true

  • lua变量没有特殊说明的话都是全局变量

  • while循环语句

    sum = 0
    num = 1
    while num <= 100 do
        sum = sum + num
        num = num + 1
    end
    print("sum = ", sum)
    
    1
    2
    3
    4
    5
    6
    7
  • for循环

    sum = 0
    for i = 1, 100 do
        sum = sum + i
    end
    
    1
    2
    3
    4
  • if-else判断语句

    if age == 40 and sex == "male" then
        print("大于40男人")
    elseif age > 60 and sex ~= "female" then  -- 不等于用~=
        print("非女人而且大于60")
    else
        local age = io.read()      -- io库的分别从stdin和stdout读写的read和write函数
        print("You age is "..age)  -- 字符串拼接操作符 ..
    end
    
    1
    2
    3
    4
    5
    6
    7
    8

# 3.5.2 Nginx+Lua环境

如果需要 Nginx 结合 Lua,需要在重新编译 Nginx,以支持 Lua 模块。

  1. 下载 LuaJIT,一个 lua 解析器
  2. 下载 nginx 对应的开发库和对应模块文件,ngx_devel_kit 和 lua-nginx-module
  3. 解压重新编译 Nginx

具体编译步骤参考手记:Nginx编译安装Lua模块 (opens new window)

# 3.5.3 Nginx调用Lua

Nginx调用Lua模块指定

Nginx的可插拔模块化加载执行,共11个处理阶段,每个阶段都可以调用对应的Lua模块指令,来实现对应的功能。

image-20210803005300607

上述有_file结尾的表示执行lua脚本文件,没有的表示执行单挑lua指令

Nginx调用Lua API接口

image-20210803005923585

# 3.5.4 Nginx+Lua示例

# 简单示例

# 使用content_by_lua指令处理响应
# lua脚本调用ngx.say接口,输出"hello, lua"作为响应
location /hello {
    default_type 'text/plain';
    content_by_lua 'ngx.say("hello, lua")';
}

# 调用ngx.req.get_headers接口从请求头x_forwarded_for中获取客户端ip
# 赋值给clientIP,再调用ngx.say接口输出响应
location /myip {
    default_type 'text/plain';
    content_by_lua '
        clientIP = ngx.req.get_headers()["x_forwarded_for"]
        ngx.say("IP:", clientIP)
        ';
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 灰度发布示例

Nginx配置:

# 根配置,调用lua脚本接收请求处理响应
location / {
    default_type 'text/html';
    content_by_lua_file /opt/app/lua/dep.lua;  #指定lua脚本位置
}

# 正式环境,请求转发到 127.0.0.1:8080
location @server {
    proxy_pass http://127.0.0.1:8080;
}

# 灰度环境,请求转发到 127.0.0.1:9090
location @server_test {
    proxy_pass http://127.0.0.1:9090;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

Lua脚本内容:

-- 根据优先级依次通过请求头,nginx变量remote_addr,获取clientIP
clientIP = ngx.req.get_headers()["X-Real-IP"]
if clientIP == nil then
    clientIP = ngx.req.get_headers()["x_forwarded_for"]
end
if clientIP == nil then
    clientIP = ngx.var.remote_addr
end

-- 加载memcache库,实例化memcached对象
local memcached = require "resty.memcached"
local memc, err = memcached:new()
if not memc then
    ngx.say("failed to instantiate memc: ", err)
    return
end
-- 连接memcache
local ok, err = memc.connect("127.0.0.1", 11211)
if not memc then
    ngx.say("failed to connect memc: ", err)
    return
end
-- 以clientIP为key,获取memcache中的value
local res, flags, err = memc.get(clientIP)
nginx.say("value key: ", res, clientIP)
if err then 
    ngx.say("failed to get clientIP: ", err)
    return
end
-- 如果命中缓存并且值为1,说明在灰度白名单,访问灰度环境
if res == 1 then 
    ngx.exec("@server_test") -- 走nginx配置的 location @server_test
    return
end
-- 没有命中缓存,走正式环境
ngx.exec("@server")  -- 走nginx配置的 location @server
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
编辑 (opens new window)
上次更新: 2023/06/04, 12:34:19
第02章-场景实践篇
第04章-架构篇

← 第02章-场景实践篇 第04章-架构篇→

最近更新
01
第01章-RabbitMQ导学
02-10
02
第02章-入门RabbitMQ核心概念
02-10
03
第03章-RabbitMQ高级特性
02-10
更多文章>
Theme by Vdoing | Copyright © 2020-2023 CodeAshen | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式