ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Java 项目实战: 外卖平台优化-Nginx部署静态资源与location匹配

Java 项目实战: 外卖平台优化-Nginx部署静态资源与location匹配 接入 Nginx: 静态资源部署与 location 路径匹配纲要「部署静态资源」是Nginx三大应用的第一个什么是静态资源服务端真实存在、可直接返回的文件为什么不用Tomcat部署静态资源sendfile零拷贝、epoll模型、无JVM开销部署方式把文件复制到html目录即可逐条解释配置listen、server_name、location、root、index实操演进部署hello.html→ 设为默认首页 → 改端口 → 多server共存真实踩坑漏分号导致reload失败、浏览器缓存导致改了没生效否是准备 hello.htmlcp 到 /usr/local/nginx/html/浏览器访问http://192.168.138.100/hello.html想让它成为首页?完成修改 index 指令为 hello.htmlnginx -t 检查nginx -s reload访问 http://192.168.138.100直接显示 hello.html一、什么是静态资源静态资源指在服务端真实存在、内容固定、可以直接返回给客户端的文件不需要任何计算或数据库查询类型扩展名说明页面.html/.htm静态HTML样式.css层叠样式表脚本.jsJavaScript图片.jpg/.png/.gif/.svg图片资源字体.woff/.woff2/.ttf字体文件音视频.mp4/.mp3媒体文件外卖平台里的具体例子移动端H5页面、后台管理的Vue打包产物、菜品图片、商家logo。与之相对的是动态资源需要程序运算生成的响应比如Spring Boot返回的JSON订单列表——每次请求结果都可能不同必须交给应用服务器。二、为什么用 Nginx 而不是 TomcatTomcat也能部署静态资源放webapps下即可但生产上几乎不会这么做。差距来自三点sendfile零拷贝Tomcat读文件发送要经历 4 次数据搬运、2 次上下文切换磁盘 → 内核缓冲区 → 用户缓冲区 → socket 缓冲区 → 网卡Nginx开启sendfile on后数据在内核态直接从文件描述符送到socket磁盘 → 内核缓冲区 → 网卡省掉两次CPU拷贝和全部用户态/内核态切换。传大文件菜品图片、视频时差距尤其明显。并发模型Tomcat一请求一线程并发受限于maxThreads默认 200。静态资源请求虽然处理快但会长时间占住线程尤其是慢速客户端。Nginx的epoll单worker就能维持数万连接慢客户端几乎不消耗额外资源。无 JVM 开销Nginx是C写的常驻内存几MBTomcat光JVM堆就要几百MB起步。把宝贵的JVM资源留给业务逻辑是常识。典型架构Nginx在最外层命中静态资源的直接返回动态请求才proxy_pass给Tomcat。/api/** 动态请求/*.html、/*.js、/*.png 静态请求客户端Nginx :80Spring Boot :8080本地 html 目录直接 sendfile 返回MySQL 主从三、部署实操第一步准备静态页面课程提供了一个hello.html内容如下!DOCTYPEhtmlhtmllangzh-CNheadmetacharsetUTF-8titlehello Nginx/title/headbodyh2hello Nginx .../h2/body/html把它放到/根目录也可以放在任意位置只要cp时写对路径。第二步复制到 html 目录cp/hello.html /usr/local/nginx/html/验证cd/usr/local/nginx/htmlls# 50x.html hello.html index.html这就是全部部署动作——因为默认配置里root html;已经指向这个目录。第三步启动并访问nginxps-ef|grepnginx浏览器访问http://192.168.138.100/hello.html看到hello Nginx ...即部署成功。访问http://192.168.138.100不带文件名则显示默认的Welcome to nginx!因为默认首页是index.html。四、关键配置逐条解释打开配置文件vim/usr/local/nginx/conf/nginx.conf核心部分server { listen 80; # 监听端口 server_name localhost; # 服务器名称域名 location / { # 匹配客户端请求 URI root html; # 指定静态资源根目录 index index.html index.htm; # 指定默认首页 } }listen—— 监听端口listen 80;Nginx在哪个端口等待连接。常见写法写法含义listen 80;监听所有网卡的80端口listen 81;监听81端口listen 127.0.0.1:80;只监听本机回环外部访问不到listen 443 ssl;HTTPSlisten 80 default_server;作为该端口的默认虚拟主机改成81后原来的80就访问不到了。这是课程里演示过的一步改端口 →reload→ 用80访问失败 → 用81访问成功。server_name—— 服务器名称server_name localhost;学习阶段没有域名就写localhost生产环境写真实域名如server_name www.example.com;。它的真正作用在于多个server监听同一端口时的分流Nginx用请求头里的Host值去匹配各server的server_name匹配到哪个就交给哪个处理。server { listen 80; server_name admin.example.com; # 后台管理 location / { root html/admin; } } server { listen 80; server_name m.example.com; # 移动端 location / { root html/mobile; } }这样一个80端口就能托管两个站点。支持通配符*.example.com和正则~^www\d\.example\.com$。location /—— 路径匹配location / { ... }location后面跟的是匹配规则/表示匹配所有请求。常见匹配方式优先级从高到低写法类型含义location /path精确匹配只匹配完全相同的URIlocation ^~ /static/前缀匹配优先匹配前缀且不再检查正则location ~ \.php$正则匹配区分大小写按正则匹配location ~* \.png$正则匹配不区分大小写按正则匹配location /通用前缀匹配兜底优先级最低外卖平台的典型配置# 精确匹配首页 location / { root html; index index.html; } # 静态资源走本地设置长缓存 location ^~ /static/ { root html; expires 7d; } # 图片单独配置 location ~* \.(jpg|jpeg|png|gif|ico|svg)$ { root html; expires 30d; access_log off; } # 动态请求转发后端 location /api/ { proxy_pass http://192.168.138.101:8080; }root—— 静态资源根目录root html;html是相对路径基准是Nginx安装目录/usr/local/nginx所以实际路径是/usr/local/nginx/html。也可以写绝对路径语义更清晰root /usr/local/nginx/html;请求http://192.168.138.100/hello.html的解析过程URI /hello.html root /usr/local/nginx/html 最终文件路径 /usr/local/nginx/html /hello.html /usr/local/nginx/html/hello.htmlindex—— 默认首页index index.html index.htm;当请求的URI以/结尾即访问目录而非具体文件时Nginx依次尝试这些文件。找到第一个存在的就返回都不存在且未开启目录列表返回403 Forbidden目录不可访问路径本身不存在返回404 Not Found多个值用空格分隔不是逗号index index.html index.htm index.php;五、把 hello.html 设为默认首页修改配置vim/usr/local/nginx/conf/nginx.conf找到index那一行注释掉原配置另起一行location / { root html; # index index.html index.htm; index hello.html; }保存退出:wq。踩坑漏写分号如果写成index hello.html ← 少了分号 }nginx -s reload会报nginx: [emerg] unexpected } in /usr/local/nginx/conf/nginx.conf:46注意报错行号 46 是花括号所在行真正的问题在上一行。Nginx把下一行的}当成了index指令的延续直到遇见{或不匹配的括号才报错。修正vim/usr/local/nginx/conf/nginx.conf :set nu# 显示行号# 找到对应行补上分号这个坑的教训改配置后先nginx -t它会直接报directive index is not terminated by ;比reload的报错更准确。重新加载nginx-t# nginx: the configuration file ... syntax is ok# nginx: configuration file ... test is successfulnginx-sreload验证访问http://192.168.138.100不带文件名现在直接显示hello Nginx ...。如果还是显示旧页面是浏览器缓存。做一次强制刷新Ctrl F5 Windows Cmd Shift R Mac或者在开发者工具Network面板勾选Disable cache。这是前端调试时的高频困惑——配置明明生效了但浏览器拿的是本地缓存。六、修改监听端口server { listen 81; # 从 80 改为 81 server_name localhost; location / { root html; index hello.html; } }nginx-tnginx-sreload验证http://192.168.138.100→ 访问不到80已无监听http://192.168.138.100:81→ 正常访问注意非80端口必须在URL里显式写出。同时别忘了防火墙放行firewall-cmd--zonepublic --add-port81/tcp--permanentfirewall-cmd--reload七、配置多个 server一个http块里可以有多个server同时监听不同端口http { include mime.types; default_type application/octet-stream; sendfile on; # 站点一80 端口默认首页 server { listen 80; server_name localhost; location / { root html; index hello.html; } } # 站点二81 端口原默认页面 server { listen 81; server_name localhost; location / { root html; index index.html index.htm; } } }nginx-tnginx-sreload现在80和81都能访问且返回不同页面。也可以让两个server监听同一端口用server_name区分需要配置hosts或真实域名才能验证server { listen 80; server_name admin.reggie.com; location / { root /usr/local/nginx/html/admin; index index.html; } } server { listen 80; server_name m.reggie.com; location / { root /usr/local/nginx/html/mobile; index index.html; } }八、外卖平台的前端部署结构把这套思路套到外卖平台上最终的静态资源目录会是/usr/local/nginx/html/ ├── backend/ # 后台管理系统Vue 打包产物 │ ├── index.html │ ├── static/ │ │ ├── css/ │ │ ├── js/ │ │ └── fonts/ │ └── favicon.ico ├── front/ # 移动端 H5 │ ├── index.html │ └── static/ └── img/ # 上传的菜品图片 ├── dish-xxxx.jpg └── setmeal-yyyy.png对应配置server { listen 80; server_name localhost; # 后台管理系统 location /backend/ { alias /usr/local/nginx/html/backend/; index index.html; try_files $uri $uri/ /backend/index.html; # 支持 history 路由 } # 移动端 location /front/ { alias /usr/local/nginx/html/front/; index index.html; try_files $uri $uri/ /front/index.html; } # 上传的图片 location /img/ { alias /usr/local/nginx/html/img/; expires 30d; access_log off; } # 动态请求转发后端 location /api/ { proxy_pass http://192.168.138.101:8080/; } }三个要点try_files是SPA必需的Vue Router用history模式时/backend/dish/list这个URI在磁盘上不存在对应文件必须回退到index.html交给前端路由处理否则刷新页面会 404alias比root更直观/backend/→/usr/local/nginx/html/backend/不需要理解拼接规则图片配expiresaccess_log off长缓存头减少重复请求关掉访问日志减少磁盘IO九、常见问题现象原因解决访问返回 404文件不在root指定的目录检查文件路径与root配置访问返回 403目录不可读或首页文件都不存在检查文件权限、index配置CSS/JS加载后页面样式全无未include mime.types或MIME类型不对检查http块里的include改了配置没生效忘记reloadnginx -s reloadreload后仍是旧页面浏览器缓存Ctrl F5强制刷新reload报unexpected }上一行漏了分号vim里:set nu定位补分号改了端口访问不到防火墙未放行新端口firewall-cmd --add-port81/tcp --permanent图片上传报 413client_max_body_size默认1m在http块调大如client_max_body_size 100m;API 速览指令作用listen port监听端口server_name name虚拟主机域名用于同端口多站点分流location [ | ^~ | ~ | ~*] uri路径匹配块符号决定匹配方式与优先级root path静态资源根目录最终路径 root 完整URIalias path路径别名最终路径 alias 去掉location前缀的剩余部分index file...默认首页空格分隔多个依次查找try_files file... fallback依次尝试文件都不存在则回退如/index.htmlexpires time设置响应缓存头Cache-Control/Expiresaccess_log off关闭该location的访问日志client_max_body_size size允许的最大请求体默认1mcp src dest复制文件到html目录完成部署vim :set nu编辑时显示行号便于定位报错行官方文档Nginx静态资源服务https://nginx.org/en/docs/http/ngx_http_core_module.html#locationNginxBeginners Guide静态内容https://nginx.org/en/docs/beginners_guide.html#staticNginxroot指令https://nginx.org/en/docs/http/ngx_http_core_module.html#rootNginxalias指令https://nginx.org/en/docs/http/ngx_http_core_module.html#aliasNginxindex指令https://nginx.org/en/docs/http/ngx_http_index_module.htmlNginxtry_files指令https://nginx.org/en/docs/http/ngx_http_core_module.html#try_files总结部署静态资源就是把文件复制到html目录。默认配置的root html;已经指向/usr/local/nginx/htmllocation /匹配所有请求index index.html指定默认首页。Nginx处理静态资源强于Tomcat核心是sendfile零拷贝 epoll高并发 无JVM开销。生产上静态资源一律走Nginx只把动态请求转发给应用服务器。五个关键指令要分清listen管端口、server_name管域名分流、location管路径匹配、root/alias管文件根路径、index管默认首页。其中root与alias的拼接规则不同——root拼完整URIalias替换掉location前缀这是静态资源 404 的头号原因。改配置的完整流程vim改 →nginx -t检查 →nginx -s reload生效 → 浏览器Ctrl F5强制刷新验证。四步缺一不可尤其是最后一步——浏览器缓存造成的改了没生效是最高频的假故障。漏分号的报错行号会滞后一行。看到unexpected }就往上翻一行找分号用vim的:set nu能快速定位。先nginx -t再reload能拿到更准确的错误信息directive is not terminated by ;。SPA部署必须加try_files。否则Vue的history路由在刷新时会出现 404因为服务端磁盘上不存在/backend/dish/list这样的文件。下一篇讲Nginx最重要的能力反向代理——把动态请求转发给后端的Spring Boot让前后端路径统一在同一个域名和端口下。
返回列表