前言
大家好,我是老马。很高兴遇到你。
我们为 java 开发者实现了 java 版本的 nginx
https://github.com/houbb/nginx4j
如果你想知道 servlet 如何处理的,可以参考我的另一个项目:
手写从零实现简易版 tomcat minicat
手写 nginx 系列
如果你对 nginx 原理感兴趣,可以阅读:
从零手写实现 nginx-01-为什么不能有 java 版本的 nginx?
从零手写实现 nginx-02-nginx 的核心能力
从零手写实现 nginx-03-nginx 基于 Netty 实现
从零手写实现 nginx-04-基于 netty http 出入参优化处理
从零手写实现 nginx-05-MIME类型(Multipurpose Internet Mail Extensions,多用途互联网邮件扩展类型)
从零手写实现 nginx-06-文件夹自动索引
从零手写实现 nginx-07-大文件下载
从零手写实现 nginx-08-范围查询
从零手写实现 nginx-09-文件压缩
从零手写实现 nginx-10-sendfile 零拷贝
从零手写实现 nginx-11-file+range 合并
从零手写实现 nginx-12-keep-alive 连接复用
从零手写实现 nginx-13-nginx.conf 配置文件介绍
从零手写实现 nginx-14-nginx.conf 和 hocon 格式有关系吗?
从零手写实现 nginx-15-nginx.conf 如何通过 java 解析处理?
从零手写实现 nginx-16-nginx 支持配置多个 server
从零手写实现 nginx-17-nginx 默认配置优化
从零手写实现 nginx-18-nginx 请求头+响应头操作
从零手写实现 nginx-19-nginx cors
一个 nginx.conf 的例子
# nginx.conf# 定义运行Nginx的用户和组
user nginx;# 主进程的PID文件存放位置
pid /var/run/nginx.pid;# 事件模块配置
events {worker_connections 1024; # 每个工作进程的最大连接数
}# HTTP模块配置
http {include /etc/nginx/mime.types; # MIME类型配置文件default_type application/octet-stream; # 默认的MIME类型# 访问日志配置access_log /var/log/nginx/access.log; # 访问日志文件路径# 错误日志配置error_log /var/log/nginx/error.log; # 错误日志文件路径# 文件传输设置sendfile on; # 开启高效文件传输tcp_nopush on; # 防止网络拥塞# Keepalive超时设置keepalive_timeout 65;# 定义服务器块server {listen 80; # 监听80端口server_name example.com; # 服务器域名# 静态文件的根目录root /usr/share/nginx/html; # 静态文件存放的根目录index index.html index.htm; # 默认首页# 定义location块,处理对根目录的请求location / {try_files $uri $uri/ =404; # 尝试提供请求的文件,如果不存在则404}}server {listen 443 ssl;server_name secure-example.com;ssl_certificate /etc/nginx/ssl/secure-example.com.crt;ssl_certificate_key /etc/nginx/ssl/secure-example.com.key;location / {root /var/www/secure-example.com;index index.html index.htm;}}}
自己解析
思路
我们可以自己写一堆代码,然后解析这个配置文件。
伪代码
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;public class NginxConfigParser {public static void main(String[] args) {Map<String, String> configMap = parseNginxConfig("/path/to/nginx.conf");System.out.println("Nginx configuration settings:");for (Map.Entry<String, String> entry : configMap.entrySet()) {System.out.println(entry.getKey() + " = " + entry.getValue());}}public static Map<String, String> parseNginxConfig(String filePath) {Map<String, String> configMap = new HashMap<>();try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {String line;String currentBlock = "";Pattern pattern = Pattern.compile("^\\s*([^#\\s][^\\s]*)\\s*([^#]+)?");while ((line = reader.readLine()) != null) {Matcher matcher = pattern.matcher(line);if (matcher.find()) {String directive = matcher.group(1);String value = matcher.group(2);if (value != null) {value = value.trim();if (value.endsWith(";")) {value = value.substring(0, value.length() - 1).trim();}}if (directive.equals("server")) {currentBlock = "server";} else if (directive.equals("location")) {currentBlock = "location";}if (!directive.isEmpty()) {configMap.put(currentBlock + "." + directive, value);}}}} catch (IOException e) {e.printStackTrace();}return configMap;}
}
实际效果
上面的内容,如果用这个方法解析,实际上并不太准确。
Nginx configuration settings:
.events = {
location.} = null
server.listen = 80
.error_log = /var/log/nginx/error.log
server.server = {
location.try_files = $uri $uri/ =404
.include = /etc/nginx/mime.types
.keepalive_timeout = 65
.user = nginx
.tcp_nopush = on
.pid = /var/run/nginx.pid
server.server_name = example.com
.} = null
.http = {
.default_type = application/octet-stream
.worker_connections = 1024
location.location = / {
server.root = /usr/share/nginx/html
server.index = index.html index.htm
.access_log = /var/log/nginx/access.log
.sendfile = on
优缺点
自己实现,可控性相对比较强。
但是缺点是比较麻烦,可能还会引入一堆问题。
三方库解析
第二种是利用三方库。
比如 https://github.com/odiszapc/nginx-java-parser
Nginx配置Java解析器
这个库帮助分析Nginx Web服务器配置文件,查找指定的参数、块、正则表达式或注释。
然后AST可以被修改并转换回纯文本文件。
maven 依赖
<dependency><groupId>com.github.odiszapc</groupId><artifactId>nginxparser</artifactId><version>0.9.3</version>
</dependency>
解析例子
package com.github.houbb.nginx4j.config;import com.github.odiszapc.nginxparser.NgxBlock;
import com.github.odiszapc.nginxparser.NgxConfig;
import com.github.odiszapc.nginxparser.NgxEntry;
import com.github.odiszapc.nginxparser.NgxParam;import java.io.IOException;
import java.util.List;public class NginxConfigParserTest {public static void main(String[] args) throws IOException {NgxConfig conf = NgxConfig.read("D:\\github\\nginx4j\\src\\test\\resources\\nginx-demo.conf");// 基本信息NgxParam pidParam = conf.findParam("pid");System.out.println(pidParam.getValue());;NgxParam worker_connectionsParam = conf.findParam("events", "worker_connections");System.out.println(worker_connectionsParam.getValue());// 模块下多级NgxParam listen = conf.findParam("http", "server", "listen"); // 示例2System.out.println(listen.getValue()); // "8889"// 首先获取 blockList<NgxEntry> servers = conf.findAll(NgxConfig.BLOCK, "http", "server"); // 示例3for (NgxEntry entry : servers) {NgxBlock ngxBlock = (NgxBlock) entry;String name = ngxBlock.getName();// valueString value = ngxBlock.findParam("listen").getValue(); // 第一次迭代返回"on",第二次迭代返回"off"System.out.println(name + "---" + value);}}}
测试日志
/var/run/nginx.pid
1024
80
server---80
server---443 ssl
转储器
NgxConfig conf = NgxConfig.read("/etc/nginx/nginx.conf");
// ...
NgxDumper dumper = new NgxDumper(conf);
return dumper.dump(System.out);
自定义的解析类
思路
我们首先进行一层封装,方便后续的接口替换。
目前底层使用 nginxparser 来统一实现。
效果
/var/run/nginx.pid
1024
80
server---80
server---443 ssl
小结
本文介绍了 nginx 配置文件的例子,和自己解析的思路。
不过还是推荐使用三方标准库来处理,这样很多情况解决的比较充分。
我是老马,期待与你的下次重逢。
开源地址
为了便于大家学习,已经将 nginx 开源
https://github.com/houbb/nginx4j