1. 问题现象与背景分析那天我正在将若依框架部署到生产环境Nginx作为反向代理服务器配置完成后发现了一个奇怪的问题Druid监控页面的CSS和JS文件全部报404错误而其他静态资源却能正常加载。这直接导致Druid监控页面样式错乱功能无法使用。若依框架RuoYi是一个基于Spring Boot的快速开发平台内置了Druid数据库连接池的监控功能。Druid的监控页面依赖静态资源如druid.js、druid.css等来实现界面展示和交互功能。正常情况下这些资源应该通过/druid/路径下的URL访问。在生产环境中我们通常会用Nginx作为反向代理将请求转发到后端的Tomcat或Spring Boot应用。我的Nginx配置中使用了正则表达式location来匹配不同的路径规则正是这个配置导致了静态资源404的问题。2. Nginx配置原貌与问题定位先来看出问题的Nginx配置片段server { listen 80; server_name example.com; location ~ ^/api/ { proxy_pass http://backend; proxy_set_header Host $host; } location ~ ^/druid/ { proxy_pass http://backend; proxy_set_header Host $host; } location / { root /var/www/html; try_files $uri $uri/ /index.html; } }这个配置看起来没什么问题但实际上会导致Druid的静态资源加载失败。原因在于Druid的监控页面会加载类似/druid/js/druid.js这样的静态资源Nginx的正则location匹配^/druid/后会将请求代理到后端应用但后端Spring Boot应用默认不会处理这些静态资源的请求关键点Druid的静态资源实际上位于Druid的jar包中需要通过Spring Boot的静态资源处理机制来访问。当Nginx直接代理这些请求时Spring Boot没有机会处理这些资源请求。3. 问题根因深度解析要彻底理解这个问题我们需要了解几个关键机制3.1 Spring Boot静态资源处理机制Spring Boot对于静态资源的处理有明确的优先级顺序首先查找/META-INF/resources/目录然后查找/resources/目录接着查找/static/目录最后查找/public/目录Druid的静态资源被打包在druid-xxx.jar的/META-INF/resources/目录下。当请求到达Spring Boot应用时DispatcherServlet会先尝试匹配Controller如果没有匹配的Controller就会交给静态资源处理器来处理。3.2 Nginx正则location的匹配行为Nginx的location匹配有以下几种形式 /path精确匹配^~ /path前缀匹配~ pattern正则匹配区分大小写~* pattern正则匹配不区分大小写在我的配置中使用了~ ^/druid/这种正则匹配它会拦截所有以/druid/开头的请求包括静态资源请求。3.3 反向代理与静态资源服务的冲突问题的本质在于Druid的静态资源需要通过Spring Boot的静态资源处理器来访问Nginx的正则location拦截了这些请求并直接代理到后端后端没有对应的Controller来处理这些请求结果就是404错误4. 解决方案与配置优化经过上述分析我们有以下几种解决方案4.1 方案一精确匹配Druid的路径修改Nginx配置只代理特定的Druid路径location /druid { proxy_pass http://backend; proxy_set_header Host $host; } location /druid/ { proxy_pass http://backend; proxy_set_header Host $host; } location /druid/ { root /var/www/html; try_files $uri $uri/ 404; }这个方案的优点是精确控制哪些路径走代理静态资源由Nginx直接处理缺点是需要明确知道哪些路径需要代理配置相对复杂4.2 方案二排除静态资源路径在正则location中排除静态资源路径location ~ ^/druid/(?!js/|css/|img/).* { proxy_pass http://backend; proxy_set_header Host $host; } location /druid/ { proxy_pass http://backend; proxy_set_header Host $host; }这个方案使用负向先行断言(?!...)来排除静态资源路径。4.3 方案三最佳实践配置结合前两种方案的优点推荐以下配置location /druid { return 302 /druid/; } location /druid/ { proxy_pass http://backend/druid/; proxy_set_header Host $host; } location /druid/login.html { proxy_pass http://backend/druid/login.html; proxy_set_header Host $host; } location ~ ^/druid/(.*\.(js|css|png|jpg|gif|ico))$ { alias /path/to/spring/boot/static/resources/; expires 30d; } location ~ ^/druid/ { proxy_pass http://backend/druid/; proxy_set_header Host $host; }这个配置实现了/druid重定向到/druid/静态资源由Nginx直接服务其他Druid路径走代理5. 实施步骤与验证5.1 实施步骤备份当前Nginx配置根据选择的方案修改Nginx配置重新加载Nginx配置sudo nginx -t sudo nginx -s reload清理浏览器缓存访问Druid监控页面验证5.2 验证方法检查静态资源是否加载成功浏览器开发者工具查看Network标签确认js/css文件返回200状态码检查代理功能是否正常登录Druid监控页面验证数据统计功能是否正常性能测试使用ab或wrk测试静态资源访问性能对比优化前后的响应时间6. 进阶优化与注意事项6.1 静态资源缓存优化对于Druid的静态资源可以设置长期缓存location ~ ^/druid/(.*\.(js|css|png|jpg|gif|ico))$ { alias /path/to/resources/$1; expires 365d; add_header Cache-Control public; }6.2 安全加固建议Druid监控页面包含敏感信息应该做安全加固修改默认路径# application.properties druid.stat-view-servlet.url-pattern/custom-monitor/*添加访问控制location ~ ^/druid/ { auth_basic Restricted; auth_basic_user_file /etc/nginx/.htpasswd; proxy_pass http://backend/druid/; }IP白名单限制location ~ ^/druid/ { allow 192.168.1.0/24; deny all; proxy_pass http://backend/druid/; }6.3 性能监控配置Nginx日志记录Druid访问情况log_format druid_log $remote_addr - $remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent $request_time $upstream_response_time; access_log /var/log/nginx/druid_access.log druid_log;7. 常见问题排查指南7.1 静态资源仍然404可能原因路径配置错误检查alias或root指向的实际路径确认文件权限Spring Boot资源处理被禁用检查spring.web.resources.add-mappings配置排查命令# 检查文件是否存在 ls -l /path/to/resources/druid/js/druid.js # 检查Nginx错误日志 tail -f /var/log/nginx/error.log7.2 代理后会话丢失现象登录后跳转又回到登录页面解决方案location ~ ^/druid/ { proxy_pass http://backend/druid/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_cookie_path /druid/ /; }7.3 性能问题如果Druid页面加载慢检查静态资源是否启用了gzipgzip on; gzip_types text/css application/javascript;考虑使用CDN分发静态资源调整Druid的监控数据采集间隔druid.stat.sql.SlowSqlMillis3000 druid.stat.logSlowSqltrue8. 经验总结与最佳实践经过这次踩坑我总结了以下几点经验谨慎使用正则location正则表达式虽然强大但容易产生意料之外的行为。在代理配置中尽量使用精确匹配或前缀匹配。理解各组件的工作机制Nginx和Spring Boot对静态资源的处理方式不同只有理解它们各自的工作原理才能正确配置。静态资源与API请求分离最好将静态资源和API请求分开处理静态资源由Nginx直接服务API请求走代理。测试要全面修改Nginx配置后不仅要测试主页面还要检查所有依赖的静态资源。监控与日志为关键路径配置专门的日志格式便于问题排查。对于若依框架的部署我现在的推荐做法是# 静态资源 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { root /path/to/static; expires 30d; access_log off; } # Druid特殊处理 location /druid { return 302 /druid/; } location /druid/ { proxy_pass http://backend/druid/; } location ~ ^/druid/(.*\.(js|css|png))$ { alias /path/to/spring/boot/resources/$1; expires 365d; } location ~ ^/druid/ { proxy_pass http://backend/druid/; } # API代理 location /api/ { proxy_pass http://backend/api/; } # 前端路由 location / { root /path/to/frontend; try_files $uri $uri/ /index.html; }这种配置结构清晰职责分明能够避免大多数代理和静态资源相关的问题。