使用Nginx OpenResty与Redis实现高效IP黑白名单管理

1、引言

在当今数字化时代,网络安全已成为企业和个人用户关注的焦点。IP黑白名单作为一种有效的网络安全策略,允许我们精确控制对Web资源的访问权限。通过白名单,我们可以确保只有可信的IP地址能够访问敏感资源;而黑名单则可以阻止恶意IP的访问,从而减少安全风险。

选择Nginx OpenResty与Redis作为实现黑白名单的解决方案,是基于以下几个原因:

  • 高性能:Nginx以其轻量级和高性能著称,适合处理高并发请求。
  • 灵活性:OpenResty通过集成Lua脚本,提供了强大的定制能力。
  • 可扩展性:Redis作为一个内存数据结构存储,支持数据的快速读写,适合实现动态的黑白名单管理。

2、简介

1、什么是OpenResty?

OpenResty是一个基于Nginx的全功能Web平台,它集成了一系列精心设计的Lua库、第三方模块和一个基于LuaJIT的轻量级Web框架。OpenResty的核心是Nginx,但它通过Lua语言扩展了Nginx的功能,使其能够构建能够处理超高并发的动态Web应用。

2、OpenResty与Nginx的关系

OpenResty是在Nginx的基础上构建的,它保留了Nginx的所有功能,并通过Lua语言扩展了其能力。这意味着你可以使用OpenResty来实现Nginx的所有功能,同时还能够利用Lua脚本来实现更复杂的业务逻辑。

3、环境安装

1、环境版本

centos 7 
redis 7.2
nginx version: openresty/1.25.3.1

2、环境安装

1、添加OpenResty仓库

# 由于公共库中找不到openresty,所以需要添加openresty的源仓库
yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo# 注意,如果上面命令提示不存在,那就先安装一下
yum install -y yum-utils
  1. 安装OpenResty
# 安装openresty
yum install -y openresty
# 安装OpenResty管理工具,帮助我们安装第三方的Lua模块
yum install -y openresty-opm

3、目录结构
​ 默认安装在/usr/local/openresty
在这里插入图片描述
看到里面有一个nginx目录,进去可以看到跟我们平常用的nginx是一模一样的,OpenResty就是在Nginx基础上集成了一些Lua模块

到这里我们就安装好了

4、启动和运行
OpenResty底层是基于Nginx的,查看OpenResty目录的nginx目录,结构与windows中安装的nginx基本一致

5、安装配置redis

sudo yum install redis -y

Redis配置主要包括设置持久化选项、网络配置、安全性设置等。以下是一个基本的配置示例:

# redis.conf
port 6379
bind 127.0.0.1
protected-mode yes
requirepass "yourpassword"

4、白名单实现

在这里插入图片描述

图例说明:

  • 客户端:发送HTTP请求的用户或应用。
  • Nginx (OpenResty):处理和管理HTTP请求,执行Lua脚本进行访问控制。
  • Lua脚本:在Nginx中运行,负责从Redis获取白名单并进行IP检查。
  • Redis:存储白名单数据,用于快速查询。
交互流程:
  1. 客户端发送请求到Nginx。
  2. Nginx调用Lua脚本进行访问控制。
  3. Lua脚本连接Redis,并查询IP是否在白名单中。
  4. Lua脚本返回查询结果给Nginx。
  5. Nginx根据结果决定是否允许请求,并返回响应给客户端

定义白名单的作用与重要性

白名单是一种安全策略,用于定义一组被信任的IP地址或实体,它们被允许访问特定的资源或服务。在Web应用中,白名单的作用尤为显著:

  • 安全性增强:限制访问权限,仅允许特定的IP地址访问敏感资源。
  • 防止滥用:减少恶意用户或爬虫对服务的滥用。
  • 流量管理:通过控制访问源,更有效地管理网络流量。

通过OpenResty Lua脚本实现白名单逻辑

在OpenResty中,我们可以使用Lua脚本来实现白名单逻辑。Lua脚本可以在Nginx的配置文件中直接编写,或者存储在外部文件中,并在配置文件中引用。

Lua脚本实现步骤:

  1. 定义白名单:在Redis中存储白名单IP地址。
  2. 访问控制:在Nginx配置中使用access_by_lua_blockaccess_by_lua_file指令调用Lua脚本。
  3. 脚本逻辑:检查请求的IP地址是否在白名单中,如果不在,则拒绝访问。

案例演示

jenkins.ownit.top.conf
这个是nginx的配置文件
最主要内容:access_by_lua_file /opt/nginx/lua_script/white.lua;

upstream jenkins-uat {server 192.168.102.20:91;
}
server {listen       80;server_name  jenkins.ownit.top;#白名单 或者 黑名单#include /opt/nginx/whitelist/corporation.conf;location / {rewrite ^/(.*)$ https://$host/$1 permanent;}access_log  /www/wwwlogs/dns.ownit.top.log;error_log  /www/wwwlogs/dns.ownit.top.error.log;}
server {listen       443 ssl;server_name  jenkins.ownit.top;#白名单 或者 黑名单#include /opt/nginx/whitelist/corporation.conf;#ssl                   on;ssl_certificate      /opt/nginx/ssl/ownit.top.crt;ssl_certificate_key  /opt/nginx/ssl/ownit.top.key;include ssl.conf;location / {access_by_lua_file /opt/nginx/lua_script/white.lua; # nginx的lua脚本proxy_pass  http://jenkins-uat;include https_proxy.conf;}access_log  /www/wwwlogs/dns.ownit.top.log;error_log  /www/wwwlogs/dns.ownit.top.error.log;}

white.lua文件

通过使用Lua脚本,在接收到HTTP请求时检查请求的IP地址是否在Redis存储的白名单中。如果IP不在白名单中,则拒绝访问。

思路

  1. 获取客户端IP和请求路径:在Lua脚本中获取客户端的IP地址和请求路径。
  2. 连接Redis:使用resty.redis模块连接Redis数据库。
  3. 权限校验:对连接的Redis进行认证。
  4. 检查IP是否在白名单中:从Redis中检查IP是否存在于白名单集合中。
  5. 返回结果:如果IP在白名单中,允许访问;否则,返回403 Forbidden状态码,拒绝访问。
  6. 释放Redis连接:将Redis连接返回到连接池中,以便复用。
-- 获取客户端IP和请求路径
local client_ip = ngx.var.remote_addr
local path = ngx.var.uri-- Redis相关配置
local redis_key_white_list = "map_request_white_list"-- 连接Redis
local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000) -- 设置超时(毫秒)
local ok, err = red:connect("127.0.0.1", 6379)
if not ok thenngx.log(ngx.ERR, "Redis连接失败: ", err)return ngx.exit(500)
end-- 权限校验
local res, err = red:auth("123456")
if not res thenngx.say("failed to authenticate: ", err)return
end-- 检查IP是否在白名单中
local is_in_whitelist, err = red:sismember(redis_key_white_list, client_ip)
if is_in_whitelist == 1 thenngx.log(ngx.INFO, "IP在白名单中: ", client_ip)
elsengx.status = ngx.HTTP_FORBIDDENngx.say("Access Denied")return ngx.exit(ngx.HTTP_FORBIDDEN)
end-- 返还redis连接到连接池
local ok, err = red:set_keepalive(10000, 100)
if not ok thenngx.log(ngx.ERR, "设置keepalive失败: ", err)
end

详细解释

  1. 获取客户端IP和请求路径

    local client_ip = ngx.var.remote_addr
    local path = ngx.var.uri
    

    这两行代码从Nginx变量中获取客户端的IP地址和请求路径,client_ip用于后续的白名单检查。

  2. Redis相关配置

    local redis_key_white_list = "map_request_white_list"
    

    定义存储白名单的Redis键。

  3. 连接Redis

    local redis = require "resty.redis"
    local red = redis:new()
    red:set_timeout(1000) -- 设置超时(毫秒)
    local ok, err = red:connect("127.0.0.1", 6379)
    if not ok thenngx.log(ngx.ERR, "Redis连接失败: ", err)return ngx.exit(500)
    end
    

    使用resty.redis模块创建Redis连接对象,并设置连接超时时间。尝试连接到Redis服务器,如果连接失败,记录错误日志并返回500错误。

  4. 权限校验

local res, err = red:auth("123456")
if not res thenngx.say("failed to authenticate: ", err)return
end

对Redis进行认证,如果认证失败,输出错误信息并停止执行。

  1. 检查IP是否在白名单中
local is_in_whitelist, err = red:sismember(redis_key_white_list, client_ip)
if is_in_whitelist == 1 thenngx.log(ngx.INFO, "IP在白名单中: ", client_ip)
elsengx.status = ngx.HTTP_FORBIDDENngx.say("Access Denied")return ngx.exit(ngx.HTTP_FORBIDDEN)
end

使用SISMEMBER命令检查IP是否在Redis的白名单集合中。如果IP在白名单中,记录信息日志;否则,返回403 Forbidden状态码并拒绝访问。

  1. 释放Redis连接
local ok, err = red:set_keepalive(10000, 100)
if not ok thenngx.log(ngx.ERR, "设置keepalive失败: ", err)
end

将Redis连接返回到连接池中,以便后续请求复用该连接。如果设置失败,记录错误日志。

在Nginx中配置Lua脚本

在Nginx的location配置中,使用access_by_lua_file指令来调用上述Lua脚本:

nginx复制代码http {```lua
http {server {listen 80;server_name example.com;location / {access_by_lua_file /opt/nginx/lua_script/white.lua;proxy_pass http://backend;}}
}

上述配置在接收到HTTP请求时,会首先执行/opt/nginx/lua_script/white.lua脚本进行白名单检查。如果通过检查,则继续将请求转发到后端服务器。

在这里插入图片描述
成功访问:
在这里插入图片描述
禁止访问:
在这里插入图片描述

5、黑名单实现

黑名单的作用与场景

黑名单是一种网络安全机制,用于识别并阻止恶意IP地址对服务器资源的访问。它在多种场景中发挥着重要作用:

  • 防止恶意攻击:通过封禁已知的攻击者IP,减少服务器遭受的恶意攻击。
  • 打击爬虫滥用:限制爬虫对网站资源的过度访问,保护数据不被滥用。
  • 减轻服务器负载:通过限制特定IP的访问频率,减轻服务器压力,提高服务稳定性。
  • DDoS防御:快速响应DDoS攻击,封禁攻击源IP,保护服务可用性。

使用Lua脚本与Redis实现动态IP封禁

OpenResty结合Redis可以实现一个高效的动态IP封禁系统。以下是实现的关键步骤:

  1. 环境配置:确保Nginx OpenResty和Redis环境准备就绪。
  2. Lua脚本编写:编写Lua脚本来动态查询和更新Redis中的黑名单状态。
  3. Nginx配置整合:在Nginx配置文件中集成Lua脚本,实现访问控制。

在这里插入图片描述

案例演示

通过使用Lua脚本,在接收到HTTP请求时检查请求的IP地址是否在黑名单中,或控制IP的访问频率,并进行相应的处理。

思路

  1. 获取客户端IP:在Lua脚本中获取客户端的IP地址。
  2. 连接Redis:使用resty.redis模块连接Redis数据库。
  3. 权限校验:对连接的Redis进行认证。
  4. 检查IP是否在黑名单中:从Redis中检查IP是否存在于黑名单集合中。
  5. 访问频次控制:对每个IP的访问频次进行限制,如果超过指定的频次,则将IP加入黑名单。
  6. 返回结果:如果IP在黑名单中,返回403 Forbidden状态码,拒绝访问;否则,允许请求继续。

Nginx 配置文件

upstream jms-uat {server 192.168.82.105:81;
}
server {listen 80;server_name jms.ownit.top;# 白名单 或者 黑名单# include /opt/nginx/whitelist/corporation.conf;rewrite ^/(.*)$ https://$host/$1 permanent;access_log /www/wwwlogs/dns.ownit.top.log;error_log /www/wwwlogs/dns.ownit.top.error.log;
}
server {listen 443 ssl;server_name jms.ownit.top;# 白名单 或者 黑名单# include /opt/nginx/whitelist/corporation.conf;ssl_certificate /opt/nginx/ssl/ownit.top.crt;ssl_certificate_key /opt/nginx/ssl/ownit.top.key;include ssl.conf;location = /core/auth/login/ {access_by_lua_file /opt/nginx/lua_script/login.lua;proxy_pass http://jms-uat;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";}location / {if ($request_uri !~ \.(html|htm|jpg|png|ico|js|css)$) {access_by_lua_file /opt/nginx/lua_script/rule.lua;}proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";proxy_pass http://jms-uat;include https_proxy.conf;client_max_body_size 0;}access_log /www/wwwlogs/dns.ownit.top.log;error_log /www/wwwlogs/dns.ownit.top.error.log;
}

location = /core/auth/login/

location = /core/auth/login/ {access_by_lua_file /opt/nginx/lua_script/login.lua;proxy_pass http://jms-uat;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";
}
解释
  • location = /core/auth/login/
    • 这是一个精确匹配的location块,仅对请求路径严格等于/core/auth/login/的请求生效。
  • access_by_lua_file /opt/nginx/lua_script/login.lua;
    • 使用OpenResty的Lua模块,指定在访问控制阶段执行/opt/nginx/lua_script/login.lua脚本。这个脚本通常用于执行认证、权限检查或其他预处理逻辑。
  • proxy_pass http://jms-uat;
    • 将匹配到的请求代理到上游服务器http://jms-uat
  • proxy_set_header Upgrade $http_upgrade;
    • 设置Upgrade请求头,支持WebSocket等协议升级。$http_upgrade变量包含原始请求中的Upgrade头字段的值。
  • proxy_set_header Connection "upgrade";
    • 设置Connection请求头为upgrade,通常与Upgrade头一起使用,以确保连接升级。

location /

location / {# 如果该location 下存在静态资源文件可以做一个判断 if ($request_uri !~ \.(html|htm|jpg|png|ico|js|css)$) {access_by_lua_file /opt/nginx/lua_script/rule.lua; 加上了这条配置,则会根据 rule.lua 的规则进行限流}proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";proxy_pass http://jms-uat;include https_proxy.conf;client_max_body_size 0;
}
解释
  • location /
    • 这是一个通配符匹配的location块,表示所有路径的请求都会匹配到这个块,除非有其他更精确的匹配块。
  • if ($request_uri !~ \.(html|htm|jpg|png|ico|js|css)$)
    • 使用if指令对请求路径进行检查。仅在请求路径不匹配指定的静态资源文件扩展名(如.html, .htm, .jpg, .png, .ico, .js, .css)时,执行后续的Lua脚本。这种检查有助于将动态资源与静态资源区分开来。
  • access_by_lua_file /opt/nginx/lua_script/rule.lua;
    • 使用OpenResty的Lua模块,指定在访问控制阶段执行/opt/nginx/lua_script/rule.lua脚本。这个脚本通常用于实现限流、防火墙或其他动态访问控制逻辑。
  • proxy_set_header Upgrade $http_upgrade;
    • 设置Upgrade请求头,支持WebSocket等协议升级。$http_upgrade变量包含原始请求中的Upgrade头字段的值。
  • proxy_set_header Connection "upgrade";
    • 设置Connection请求头为upgrade,通常与Upgrade头一起使用,以确保连接升级。
  • proxy_pass http://jms-uat;
    • 将匹配到的请求代理到上游服务器http://jms-uat
  • include https_proxy.conf;
    • 包含额外的配置文件https_proxy.conf,该文件可能包含HTTPS代理相关的其他配置项。
  • client_max_body_size 0;
    • 设置客户端请求体的最大大小为0,表示不限制请求体的大小。

这两个location块主要用于处理不同路径的请求,并在访问控制阶段使用Lua脚本进行相应的逻辑处理。精确匹配的/core/auth/login/路径专用于特定的认证或预处理,而通配符匹配的/路径则处理所有其他请求,并进行动态访问控制逻辑。两者共同确保了Nginx服务器的灵活性和安全性。

Lua脚本 (rule.lua)

-- 连接池超时回收毫秒
local pool_max_idle_time = 10000
-- 连接池大小
local pool_size = 100
-- redis 连接超时时间
local redis_connection_timeout = 100
-- redis host
local redis_host = "192.168.102.20"
-- redis port
local redis_port = "6379"
-- redis auth
local redis_auth = "123456"
-- 封禁IP时间(秒)
local ip_block_time = 120
-- 指定ip访问频率时间段(秒)
local ip_time_out = 10
-- 指定ip访问频率计数最大值(次)
local ip_max_count = 60-- 错误日志记录
local function errlog(msg, ex)ngx.log(ngx.ERR, msg, ex)
end-- 释放连接池
local function close_redis(red)if not red thenreturnendlocal ok, err = red:set_keepalive(pool_max_idle_time, pool_size)if not ok thenngx.say("redis connct err:", err)return red:close()end
end-- 连接redis
local redis = require "resty.redis"
local client = redis:new()
local ok, err = client:connect(redis_host, redis_port)
-- 连接失败返回服务器错误
if not ok thenreturn
end
-- 设置超时时间
client:set_timeout(redis_connection_timeout)-- 优化验证密码操作
local connCount, err = client:get_reused_times()
-- 新建连接,需要认证密码
if 0 == connCount thenlocal ok, err = client:auth(redis_auth)if not ok thenerrlog("failed to auth: ", err)returnend
elseif err thenerrlog("failed to get reused times: ", err)return
end-- 获取请求ip
local function getIp()local clientIP = ngx.req.get_headers()["X-Real-IP"]if clientIP == nil thenclientIP = ngx.req.get_headers()["x_forwarded_for"]endif clientIP == nil thenclientIP = ngx.var.remote_addrendreturn clientIP
endlocal clientIp = getIp()local incrKey = "limit:all:count:" .. clientIp
local blockKey = "limit:all:block:" .. clientIp-- 查询ip是否被禁止访问,如果存在则返回403错误代码
local is_block, err = client:get(blockKey)
if tonumber(is_block) == 1 thenngx.exit(ngx.HTTP_FORBIDDEN)close_redis(client)
endlocal ip_count, err = client:incr(incrKey)
if tonumber(ip_count) == 1 thenclient:expire(incrKey, ip_time_out)
end
-- 如果超过单位时间限制的访问次数,则添加限制访问标识,限制时间为ip_block_time
if tonumber(ip_count) > tonumber(ip_max_count) thenclient:set(blockKey, 1)client:expire(blockKey, ip_block_time)
endclose_redis(client)

在这里插入图片描述
成功访问:
在这里插入图片描述

失败访问:
在这里插入图片描述

参考文档:
https://www.cnblogs.com/KingArmy/p/18019489
https://blog.csdn.net/qq_45503196/article/details/134648292

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

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

相关文章

嵌入式人工智能(2-树莓派4B开发板硬件环境搭建)

1.硬件开发环境(T型板) 树莓派4B开发板需要搭配面包板,T型板将40个GPIO口引出,再将T型板插到面包板上面。这个地方需要注意插接的方向,由于插树莓派引脚的排线没有防呆设计,因此,请注意方向&am…

第二证券:电影暑期档持续升温 农机自动驾驶驶入快车道

农机自动驾驶打开驶入快车道 得益于农机补贴、土地流通、高标准农田制造等方针引导,叠加技术突围和用户降本增效的内生需求,我国正处于农业2.0向农业3.0的过渡阶段。其间农机自动驾驶系统是结束农业3.0(即自动化)的要害并迎来快速…

maptalks点聚合切换坐标系后点聚合消失

原因:因为坐标系投影问题 解决方法:切换坐标系后,重新把请求到的点位数据插入到的图层删除掉,重新插入图层就可以解决了 // 先移除已存在的同名图层 this.map.removeLayer(cluster);// 然后添加新的图层this.map.addLayer(this.c…

装饰模式:动态扩展对象的功能

在软件设计中,我们常常需要在不改变现有代码的基础上,给对象添加新的功能或责任。装饰模式(Decorator Pattern)是一种常用的设计模式,它允许我们在运行时动态地给对象添加新的行为,而无需修改原有的类结构。…

Linux/C++:Json--网络编程中的奇妙小工具

目录 一、什么是Json 二、Josn基本结构 2.1Josn对象 2.2C使用Josn 2.3.1解析Josn格式的数据 2.4Linux编程(vscode)使用Josn 一、什么是Json JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式,它是基于JavaScript语言的子集,但是独立于…

PyCharm软件初始化配置

安装完pycharm后,需要对其进行个性化设置,分别设置方法如下 目录 一、修改主题二、修改默认字体和大小三、设置拖动滚轮改变字体大小四、常见快捷键 一、修改主题 1、界面右上角点击红框的内容 2、选择Theme选项 3、选择对应的主题 第一二个是白色主题…

树莓派配置vsftpd被动模式使用frp外网端口映射实现外网连接ftp

sudo apt-get install vsftpd /etc/vsftpd.conf anonymous_enableNO # 禁用匿名用户 local_enableYES # 允许本地用户登录 write_enableYES # 允许修改权限 #chroot_local_userYES # 将用户限制在其主目录 百度关键字 frp vsftp 关闭主动模式登录 connect_from_port_…

电池技术的未来:BMS的创新与应用

目录 一、什么是BMS? 二、BMS的核心功能 三、为什么BMS如此重要? 四、应用领域 五、未来展望 随着电动汽车、储能系统以及各种便携式设备的普及,电池技术的发展变得至关重要。而在这一领域中,电池管理系统(BMS&am…

直播美颜工具开发教学:视频美颜SDK集成详解

本篇文章,笔者将详细介绍如何在直播应用中集成视频美颜SDK,让你的直播画面焕然一新。 一、什么是视频美颜SDK? 视频美颜SDK是一种软件开发工具包,提供了视频处理和图像增强功能。通过集成视频美颜SDK,开发者可以轻松…

可视化作品集(14)智慧旅游和智慧景区,洞悉一切。

智慧旅游和智慧景区的可视化大屏可以带来以下几个方面的好处: 1. 提升游客体验: 通过可视化大屏,游客可以方便地获取到景区地图、交通信息、景点介绍、活动安排等信息,帮助游客更好地规划行程,提升游览体验。 2. 提供…

超越99%动画!我测试了Luma AI视频的首尾帧,流畅度NO.1?

关键帧通常用于控制动画中的运动、形状变化、颜色变化、透明度等属性,以及视频和音频编辑中的剪辑、效果和音频级别。 最近一段时间,玩可灵AI玩得比较多(国产免费速度快),luma上回写了一篇文章后就没有接着使用(排队生…

2024年上半年信息系统项目管理师——综合知识真题题目及答案(第1批次)(2)

2024年上半年信息系统项目管理师 ——综合知识真题题目及答案(第1批次)(2) 第21题:在一个大型信息系统项目中,项目经理发现尽管已经建立了沟通机制,但团队间的沟通依然不畅,项目风险…

【python模块】Selenium

声明:本文档或演示材料仅供教育和教学目的使用,任何个人或组织使用本文档中的信息进行非法活动,均与本文档的作者或发布者无关。 文章目录 Selenium库功能介绍环境准备示例代码 Selenium库 Selenium库是一个强大的Web自动化工具,…

堆、栈和队列(数据结构)

堆、栈和队列(数据结构) 这里写目录标题 堆、栈和队列(数据结构)**栈****队列**堆(Heap)()队列(Queue)(FIFO)栈(Stack&…

【Rust】字符串String类型学习

什么是String Rust的核心语言中只有一个String类型,那就是String slice,str通常被当作是&str的借用。String类型是通过标准库提供的,而不是直接编码到核心语言中,它是一个可增长的、可变的、utf-8编码的类型。str和String都是utf-8编码的…

Faiss原理和使用

参考自https://github.com/facebookresearch/faiss/wiki,https://blog.csdn.net/Kaiyuan_sjtu/article/details/121551473 Faiss Faiss是一个用于高效相似性搜索和密集向量聚类的库。它包含搜索任意大小的向量集(大小由RAM决定)的算法。它还…

【vue教程】一. 环境搭建与代码规范配置

目录 引言Vue 框架概述起源与设计理念核心特性优势 Vue 开发环境搭建环境要求安装 Vue CLI创建 Vue 项目项目结构介绍运行与构建 组件实例基础模板响应式更新 代码规范为什么要使用代码规范在 Vue 项目中使用 ESLint 、PrettierESLint配置 ESLintrules 自定义错误级别 Prettier…

推理的判定定理三种验证方式

1. 真值表技术 2. 公式转换法 3. 主析取范式法 参考:离散数学-电子科技大学

数据结构第21节 归并排序以及优化方案

归并排序(Merge Sort)是一种分治策略的排序算法。它将一个大数组分成两个子数组,递归地对它们进行排序,然后将排序后的子数组合并成一个有序数组。 Java代码实现: public class MergeSort {public static void main(…

4.Flink程序编程规范

目录 概述 概述 Flink程序编程规范 官网文档速递 1.Obtain an execution environment 获取执行环境2.Load/create the initial data 加载/创建初始数据 > 数据接入3.Specify transformations on this data 针对数据做处理操作 > 数据处理4.Specify where to put the re…