尧图精选

Mac上安装配置Nginx部署前后端分离项目:以黑马苍穹外卖为例

🕒 发布时间:2026/10/1 13:50:23 📁 来源:尧图网络
1. 为什么黑马苍穹外卖项目要在Mac上部署nginx1.1 苍穹外卖的典型前后端分离架构先把这个项目的底子摸清楚。黑马苍穹外卖是一套非常标准的Java全栈教学项目后端基于Spring Boot开发对外暴露的是一堆RESTful接口端口默认走8080前端则是Vue工程本地开发时通过Vite或Webpack启一个Dev Server跑在5173或8081这种端口上。日常开发时前后端各跑各的接口联调用代理插件转发一下就行不会觉得缺了什么。但一旦进入联调、演示、部署验证阶段问题就来了。前端打包后的资源是纯静态文件HTML、CSS、JS、图片它需要一个Web服务器来托管后端接口跑在8080端口前端页面访问时如果直接写死http://localhost:8080跨域问题、环境切换问题全都会冒出来。这时候nginx就是最顺手的那个中间层。nginx在这个项目里实际干了三件事第一托管前端打包出来的静态文件第二把/api开头的请求反向代理到后端的Spring Boot服务第三统一入口端口让你只需要记住一个地址比如http://localhost就能同时访问页面和接口。1.2 nginx在项目里到底干了什么活很多初学者容易把nginx想得太玄其实它就是一台轻量级的Web服务器加反向代理服务器。在苍穹外卖这种项目里它的角色可以理解成一个前台接待用户浏览器来了一个请求如果是想看页面nginx直接从磁盘上把index.html、app.js这些静态文件拿出来返回如果是想查数据、下单、登录请求路径里带了/api前缀nginx就把这个请求转交给后面真正干活的Spring Boot服务拿到结果后再原样送回给浏览器。这样做最直接的好处有三个。第一是解决了跨域因为浏览器访问的是http://localhost请求后端也是通过http://localhost/api同源策略轻松满足不需要在后端代码里写一堆CORS配置。第二是隐藏了后端真实服务地址外部只知道nginx的地址不知道后面有几台后端服务、跑在什么端口。第三是将来项目上线以后如果后端要多开几个实例扛流量nginx前面配置一个负载均衡就能搞定不需要动前端代码。1.3 Mac作为开发部署环境的特殊性Mac上部署nginx和Linux服务器上部署大思路完全一样但有几个细节差异必须单独说。首先是安装方式Linux上常见做法是apt install nginx或yum install nginxMac上最主流的是通过Homebrew安装装完之后文件目录结构和Linux发行版有区别这一点坑了不少人——照着网上Linux的教程改配置结果路径压根对不上。其次是权限问题Mac的系统保护机制对/usr/local、/opt/homebrew这些目录有额外限制如果操作不当启动nginx时容易踩Permission denied的坑。第三是端口占用Mac上很多开发软件喜欢占80端口或8080端口比如自带的Apache、其他开发服务器、Docker容器经常导致nginx启动报address already in use。另外还有一个很实际的点很多人是在Mac上开发调试最后把项目部署到云服务器上。如果在Mac上把整套流程跑通了到了Linux服务器上无非就是换个安装命令的事所以拿Mac当演练场成本低、反馈快特别适合把nginx这套东西吃透。2. Mac上安装nginx的几种方式与选择2.1 用Homebrew安装nginxMac上安装nginx我实测下来最省心的就是Homebrew。如果你已经装好了brew一条命令的事brew install nginx装完之后先别急着用先看一眼安装输出里面会明确告诉你几个关键信息配置文件在哪个路径、默认端口是多少、怎么通过brew services管理nginx。这里要特别提醒一个点Intel芯片Mac和Apple Silicon芯片Mac的路径前缀不一样。Apple SiliconM1/M2/M3上Homebrew默认装在/opt/homebrewIntel机型上装在/usr/local。默认情况下nginx的主配置路径是# Apple Silicon /opt/homebrew/etc/nginx/nginx.conf # Intel /usr/local/etc/nginx/nginx.conf你可以顺手验证一下自己的brew前缀brew --prefix拿到结果就明白自己该去哪个目录找配置文件了。2.2 brew安装时的常见报错和解决办法按照网上的教程装brew很多人第一步就卡住了。比较常见的报错有这么几类。第一类Command Line Tools未安装。报错信息里通常会出现xcode-select: error: command line tools are already installed或者提示找不到git、clang之类。解决办法是在终端执行xcode-select --install系统会弹窗让你安装Xcode Command Line Tools装完后重新执行brew安装命令。第二类下载速度极慢或者直接卡住。brew安装时要从GitHub拉取目录仓库网络情况不好的时候确实很折磨。解决办法是切换国内镜像源中科大、清华、阿里云都有brew镜像。以中科大的方式为例在终端设置环境变量后重新安装export HOMEBREW_BREW_GIT_REMOTEhttps://mirrors.ustc.edu.cn/brew.git export HOMEBREW_CORE_GIT_REMOTEhttps://mirrors.ustc.edu.cn/homebrew-core.git export HOMEBREW_BOTTLE_DOMAINhttps://mirrors.ustc.edu.cn/homebrew-bottles第三类权限不足。如果你是用普通用户安装而/opt/homebrew目录的属主不是当前用户会碰到Permission denied。最粗暴的解决办法是sudo chown -R $(whoami) /opt/homebrew但这里我多说一句如果你不清楚这台Mac的管理员情况优先用sudo去执行brew命令而不是大面积修改目录权限避免影响系统其他功能。2.3 验证安装结果安装完成后用下面几个命令确认nginx能不能正常跑起来nginx -v nginx -t brew services start nginxnginx -v用来查看版本号nginx -t用来测试配置语法如果输出syntax is ok和test is successful说明配置没问题。brew services start nginx会把nginx注册成后台服务开机自启适合长期使用如果你只想临时跑一下用nginx命令直接启动不需要注册服务。启动后在浏览器访问http://localhost:8080看到Welcome to nginx的页面说明安装成功了。这里默认端口是8080不是Linux发行版常见的80端口别搞混。3. 搞懂nginx目录结构与核心配置3.1 Mac上nginx的文件都放在哪了nginx装好之后有几个目录你最好心里有数用途Apple Silicon路径Intel路径主配置/opt/homebrew/etc/nginx/nginx.conf/usr/local/etc/nginx/nginx.conf服务器配置目录/opt/homebrew/etc/nginx/servers//usr/local/etc/nginx/servers/默认网页根目录/opt/homebrew/var/www/usr/local/var/www日志目录/opt/homebrew/var/log/nginx//usr/local/var/log/nginx/实际使用中我不太建议把所有配置都塞进nginx.conf写多了文件又长又乱还容易误改。更好的习惯是nginx.conf里只保留全局配置和http块的公共设置每个站点单独建一个配置文件放在servers/目录下有些版本是sites-enabled/用include指令引入。后期维护的时候一个项目对应一个文件想禁用某个站点直接移走这个文件就行清晰得很。3.2 配置文件逐段拆解先看一份最基本的nginx.conf注意我已经把注释简化了方便逐块理解# 以哪个用户身份运行Mac上直接用当前用户即可 user staff; # 工作进程数一般设为auto让nginx自己按CPU核数来 worker_processes auto; # 错误日志级别和路径 error_log /opt/homebrew/var/log/nginx/error.log notice; # 进程ID存放位置管理nginx进程时要用 pid /opt/homebrew/var/run/nginx.pid; events { # 每个工作进程的最大连接数 worker_connections 1024; } http { # 引入mime类型映射让nginx知道.xxx后缀对应什么Content-Type include mime.types; default_type application/octet-stream; # 访问日志格式 log_format main $remote_addr - $remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent $http_x_forwarded_for; # 访问日志路径 access_log /opt/homebrew/var/log/nginx/access.log main; # 开启sendfile静态文件传输效率高很多 sendfile on; keepalive_timeout 65; # gzip压缩前端资源体积能小一大截 gzip on; gzip_types text/plain text/css application/json application/javascript text/xml application/xml; # 引入servers目录下所有以.conf结尾的站点配置 include servers/*.conf; }events块里的worker_connections决定了并发能力上限。计算公式很简单最大并发连接数约等于worker_processes * worker_connections。对于苍穹外卖这种开发调试项目1024绰绰有余不用刻意调大。http块里的gzip开关很多人容易漏掉。前端打包出来的JS和CSS动辄几百KB开启gzip后传输体积能压缩掉60%到70%页面打开速度肉眼可见地变快。在本地环境跑苍穹外卖时也许感觉不明显但把这个配置带到服务器上效果立竿见影。3.3 最容易搞错的服务块匹配规则每个站点配置里都会有server块它代表一个虚拟主机。最核心的匹配规则有两个维度listen端口和server_name域名。比如你配置了server { listen 80; server_name localhost; ... }那么浏览器访问http://localhost时命中这个配置。如果同一个端口下有多个server块但server_name不同nginx会根据请求头里的Host字段来区分。要特别注意如果你既没有配置server_name又没有指定default_servernginx会把第一个server块当作默认站点访问本机IP时也会走到它身上——这是个很容易踩的坑多个项目配置文件放在servers目录下时加载顺序就直接决定了谁接盘默认请求。location块里的匹配优先级也是重点。规则可以概括成精确匹配最优先^~前缀匹配其次正则匹配~或~*再次最后是普通前缀匹配。在苍穹外卖这种前端单页应用里最常用的两个location就是根路径/和接口路径/api/前者负责静态页面和前端路由后者负责转发后端请求。把这两个规则理清后面实战配置就不会发怵。4. 黑马苍穹外卖项目nginx配置实战4.1 部署思路静态页面交给nginx动态请求转给后端苍穹外卖项目前端打完包之后会生成一个dist目录里面是index.html、assets之类的静态资源。后端的Spring Boot服务正常跑在localhost:8080。nginx的作用就是在两者之间搭一座桥。整体访问流程是浏览器输入http://localhost80端口nginx收到请求判断路径如果是根路径或静态资源路径直接返回dist目录下的文件如果路径以/api开头转发到http://localhost:8080后端处理完业务返回JSON数据nginx原样回传给前端这样前端代码里所有请求都写成相对路径/api/...不写死IP和端口不管部署到Mac还是云服务器只要nginx配置对应调整就行。4.2 配置静态资源托管先建一个站点配置文件比如/opt/homebrew/etc/nginx/servers/sky-take-out.conf内容如下server { listen 80; server_name localhost; # 前端打包产物目录改成你自己的实际路径 root /Users/mac/Projects/sky-take-out/dist; index index.html; location / { try_files $uri $uri/ /index.html; } }这段配置里最关键的是try_files $uri $uri/ /index.html;。它的作用是当用户刷新页面时如果访问的是像/order/list这种前端路由服务器上并没有这个真实文件nginx就回退到index.html由前端路由接管。不写这一行你刷新页面就会看到404。把虚拟目录路径替换成你本机实际的dist路径后先测试配置nginx -t确认没问题后重新加载nginx -s reload这时候访问http://localhost你应该能看到苍穹外卖的登录页了。4.3 配置反向代理解决跨域页面能打开只是第一步点击登录的时候你会发现请求全部失败控制台报跨域错误或者404。原因很简单前端页面在80端口后端接口在8080端口浏览器直接发请求到8080就跨域了或者你前端把后端地址写死成localhost:8080导致地址不一致。解决办法就是在之前的server块里增加一个location块做反向代理server { listen 80; server_name localhost; root /Users/mac/Projects/sky-take-out/dist; index index.html; location / { try_files $uri $uri/ /index.html; } # 后端接口反向代理 location /api/ { proxy_pass http://localhost:8080; 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_pass http://localhost:8080;后面的URL没有带结尾的斜杠。这种情况下nginx会把完整的原始URI包括/api前缀转发给后端后端收到的请求还是/api/...与你后端Controller里定义的RequestMapping(/api/...)是对应的。如果proxy_pass写成http://localhost:8080/;nginx在转发时会把匹配到的/api/前缀替换掉后端收到的就变成了/...大概率直接404。这个斜杠的区别建议你亲手改一次试一试踩过一次坑基本就长记性了。另外苍穹外卖项目里有WebSocket通信比如订单状态推送WebSocket在nginx里需要额外处理否则会一直握手失败。在同一个server块里加上location /ws/ { proxy_pass http://localhost:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_read_timeout 3600s; }proxy_http_version 1.1和Upgrade、Connection这两个头是WebSocket代理的核心缺一不可。proxy_read_timeout设置长一点避免连接空闲时间稍长就被nginx掐断。4.4 可选负载均衡配置虽然本地开发用不上但既然学nginx负载均衡是绕不开的经典功能。如果你后端起多个实例来做测试比如8080和8081各跑一个用upstream就能轻松实现轮询转发。# 定义一组后端服务器 upstream sky_backend { server localhost:8080; server localhost:8081; } server { listen 80; server_name localhost; root /Users/mac/Projects/sky-take-out/dist; index index.html; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://sky_backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }默认策略是轮询每个请求依次分给8080、8081。想让某个实例多扛点流量可以在server后面加weight参数比如server localhost:8080 weight3;。这只是最基本的用法生产环境里还有ip_hash、least_conn等策略但原理都不难看一遍官方文档就能上手。4.5 启动、重载与验证配置写好后的完整操作流程# 1. 检查配置语法 nginx -t # 2. 加载新配置不会中断现有连接 nginx -s reload # 3. 查看nginx进程和监听端口 ps -ef | grep nginx lsof -i :80验证时从两个维度去检查一是浏览器访问http://localhost页面能正常渲染、样式和图片都加载出来二是打开浏览器开发者工具切到Network面板刷新页面看到/api/...的请求返回200响应体是JSON数据说明反向代理通了。还有一个技巧直接看nginx日志。访问日志在/opt/homebrew/var/log/nginx/access.log报错信息在error.log。排查问题时先看error.log很多莫名其妙的404和502都是在这里露出真相的。5. 常见问题与排查心得5.1 端口被占用现象执行nginx启动时终端提示bind() to 0.0.0.0:80 failed (48: Address already in use)。原因80端口已经被其他程序占用。Mac上最常见的是系统自带的Apache或者你自己起过其他Web服务。排查lsof -i :80看输出结果里是哪个进程占了端口。如果是httpd说明Apache在跑用sudo apachectl stop停掉。如果是你自己之前起的服务用kill结束对应进程。这里有个建议开发调试阶段如果80端口一直被各种服务抢占干脆把nginx的listen改成8080或8888省得天天跟端口打架。只要前端页面访问的端口和nginx监听的端口保持一致即可。5.2 前端页面能开但接口报404现象页面加载正常但登录、查询列表等接口请求返回404。排查方向逐层看请求到底有没有到达后端。首先确认后端服务本身是好的直接访问http://localhost:8080/api/xxx如果后端能返回数据说明问题出在代理配置上。其次看nginx日志access.log里会记录转发情况。重点检查两点一是请求是否真的命中了location /api/二是proxy_pass后面到底有没有多余的斜杠。大部分404问题都是proxy_pass的URI替换规则没搞明白导致的。我的建议是只要后端接口路径本身就带/api前缀proxy_pass后面的地址就不要加斜杠让它原样转发省心。5.3 页面能开但接口报502现象接口请求返回502 Bad Gateway。原因nginx成功把请求转发给了后端地址但后端没有响应。典型情况有两个Spring Boot服务根本没启动或者监听端口跟nginx配置的不一致。排查# 确认后端端口有没有在监听 lsof -i :8080 # 看后端日志另外还有一种隐蔽情况后端服务启动在IPv6地址上而nginx转发用的是IPv4的localhost。比如Spring Boot在Mac上如果绑定了::1nginx转发到127.0.0.1:8080就会连不上。解决办法是配置文件里明确写server.port8080同时设置server.address127.0.0.1或者nginx转发地址也统一用一个。5.4 静态资源更新了但页面还是旧的现象前端代码重新npm run build打包后浏览器刷新页面还是旧版本。原因浏览器缓存了旧的JS、CSS文件或者nginx本身的缓存策略。解决办法前端打包时给文件名加上hashVue CLI和Vite默认就会打hash每次构建后文件名都不同浏览器自然重新拉取。真遇到顽固缓存浏览器开发工具里勾选Disable cache再刷新或者用Command Shift R强制刷新。如果想让nginx在响应头里主动告诉浏览器缓存策略可以加location ~* \.(png|jpg|jpeg|gif|ico|svg|css|js)$ { expires 7d; add_header Cache-Control public, max-age604800; }这套配置适合图片等不常变的资源开发阶段建议先不加不然每次改完样式刷新还是旧效果容易产生“代码没生效”的错觉。5.5 日志排查速查表日志路径典型问题访问日志/opt/homebrew/var/log/nginx/access.log请求是否到达nginx、返回状态码错误日志/opt/homebrew/var/log/nginx/error.log配置文件语法错误、端口绑定失败、上游连接失败后端日志取决于Spring Boot配置接口是否报错、SQL是否异常、服务是否正常启动排查问题时我的习惯是“从前到后”先在浏览器按F12看请求状态再从nginx access.log确认请求有没有到这一层最后看后端日志判断是不是业务代码出了问题。大部分联调问题都能在这一条链路里定位到。6. 给新手的几点配置习惯建议第一个建议是把配置拆文件。一个站点一个配置文件放在servers/目录下命名清晰比如sky-take-out.conf不要所有站点都堆在nginx.conf里。改配置之前先备份一份用nginx -t检查后再reload这是最基本的操作规范。第二个建议是注意reload和restart的区别。nginx -s reload是平滑重载能保留现有连接适合配置变更nginx -s stop是强制停止会掐断所有连接。日常改配置用reload就够了千万别动不动就重启。第三个建议是理解Mac环境和Linux环境的差异。Homebrew装的nginx默认以当前用户运行日志和缓存目录都在/opt/homebrew下Linux上多数以nginx用户运行目录在/etc/nginx和/var/log/nginx。换环境部署时路径和权限是首先要核对的两件事。最后一个实际操作中的体会拿黑马苍穹外卖这种真人项目练手nginx比单纯看教程效果好太多了。因为项目本身有前端、有后端、有代理需求你会真正遇到404、502、跨域、缓存这些五花八门的问题每一个问题排下来对nginx的理解都会深一层。在Mac上把这一整套跑通回头往云服务器上部署其实就是一个换安装命令、换配置路径的过程底层的逻辑完全通用。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →