Day01 【苍穹外卖】Nginx反向代理与Swagger接口文档实战

📅 发布时间:2026/7/4 13:54:05 👁️ 浏览次数:
Day01 【苍穹外卖】Nginx反向代理与Swagger接口文档实战
1. 从零开始为什么我们需要Nginx和Swagger大家好我是老张一个在后端和运维领域摸爬滚打了十来年的老码农。今天咱们不聊那些虚头巴脑的概念直接上手一个真实的项目——“苍穹外卖”的管理后台。很多刚接触前后端分离开发的朋友第一个拦路虎往往不是写代码而是怎么让前端页面和后端服务“对上话”以及怎么把接口清晰地告诉前端同事。我当年也踩过不少坑比如前端请求死活到不了后端或者接口文档更新不及时导致联调时鸡同鸭讲。“苍穹外卖”这个项目前端用Vue开发用Nginx来跑后端是咱们熟悉的Spring Boot在IDEA里启动。听起来很简单对吧但问题来了前端运行在80端口后端跑在8080端口浏览器有同源策略限制你直接让前端去请求http://localhost:8080/admin/xxx大概率会报跨域错误。这就是我们第一个要解决的问题反向代理。你可以把Nginx想象成一个非常专业的“前台接待”或者“路由器”。所有来自浏览器的请求比如访问localhost都先打到这个“前台”这里。这个“前台”一看哦你这个请求是来找后端API的比如路径里带/api/它就不自己处理了而是转身把请求原封不动地转交给后面办公室里的“后端开发团队”也就是localhost:8080。对于浏览器来说它只和“前台”Nginx打交道根本不知道后面还有谁这样既解决了跨域问题又隐藏了后端服务的真实地址更安全。解决了通信问题下一个头疼的就是接口文档。总不能每次都靠嘴说或者写个Word文档丢过去吧改个参数还得同步更新文档太容易出错。这时候Swagger这里我们用它的增强版Knife4j就派上用场了。它就像一个“代码即文档”的自动化工具。你在写Controller的时候顺手加几个注解比如这个接口是干嘛的ApiOperation参数是什么ApiModelProperty。项目一启动Swagger就能自动扫描这些注解生成一个漂亮的、交互式的网页文档。前端同事不仅可以看还能直接在这个网页上填参数、点“发送”来测试接口所见即所得联调效率翻倍。所以今天咱们就手把手把“苍穹外卖”项目的这个通信和文档的基建给搭起来让你以后做任何前后端分离项目都能直接套用这个套路。2. 实战第一步配置Nginx反向代理打通前后端任督二脉好了理论说完咱们动真格的。首先你得确保电脑上已经装好了Nginx。如果还没装去官网下载个稳定版解压就能用或者用包管理工具如brew、apt-get安装也行这里不赘述。我们的目标是把前端Vue项目跑起来并且让它能通过Nginx顺利访问到后端Spring Boot的接口。2.1 部署前端Vue项目到Nginx前端同事会把Vue项目打包生成一个dist文件夹。你的任务就是把这个文件夹里的所有东西一股脑儿地扔到Nginx的html目录下。比如我的Nginx在D:\nginx-1.20.1那我就把dist里的内容复制到D:\nginx-1.20.1\html\里面。接着用记事本或任何代码编辑器打开Nginx的配置文件conf/nginx.conf。找到里面的server块它大概长这样server { listen 80; # 监听80端口 server_name localhost; # 服务器名 location / { root html; # 这里是关键根目录指向html文件夹 index index.html index.htm; # 默认找index.html } # 其他配置... }这个配置的意思很简单当有人访问http://localhost时Nginx就会去html目录下找index.html文件而这个文件正是我们Vue项目的入口。保存配置文件后启动Nginx双击nginx.exe或命令行执行nginx然后在浏览器打开http://localhost你应该就能看到“苍穹外卖”的登录页面了。如果页面一片空白或者有JS加载错误别慌大概率是打包路径问题可以检查下Vue项目的publicPath配置或者看看浏览器控制台的报错信息。2.2 配置反向代理让/api请求直达后端前端页面出来了但点击登录没反应打开浏览器的开发者工具F12切换到Network网络标签页你会发现点击登录时前端发送的请求地址是http://localhost/api/employee/login。这个请求目前被Nginx的location /规则处理了Nginx会去html目录下找api/employee/login这个文件或文件夹显然找不到于是返回404。我们的目的是把这个请求“转交”给后端的http://localhost:8080/admin/employee/login。这就需要用到Nginx的反向代理功能。我们在刚才的server块里再添加一个location规则专门处理以/api/开头的请求。修改后的配置如下server { listen 80; server_name localhost; # 前端静态资源 location / { root html; index index.html index.htm; } # 反向代理配置处理所有以 /api/ 开头的请求 location /api/ { # proxy_pass 是核心指令把请求转发到指定的代理服务器 proxy_pass http://localhost:8080/admin/; # 可选设置一些请求头确保后端能获取到原始客户端信息 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }我来解释一下这个“魔法”是怎么发生的当Nginx收到http://localhost/api/employee/login这个请求时location /api/规则被匹配。proxy_pass http://localhost:8080/admin/;这行命令开始工作。它会将请求的/api/前缀替换成http://localhost:8080/admin/。所以最终的转发地址就变成了http://localhost:8080/admin/employee/login完美地对上了我们后端Spring Boot控制器EmployeeController上的RequestMapping(/admin/employee)和PostMapping(/login)。配置完成后记得重启Nginx命令行执行nginx -s reload让配置生效。这时再在前端点击登录Network里看到的请求地址没变但状态码应该变成了200并且能收到后端返回的token等数据了恭喜你前后端通信的桥梁正式通车2.3 进阶玩法配置负载均衡让后端服务更有弹性如果你的项目访问量上来了或者你想做高可用一个后端服务实例可能不够。Nginx的反向代理天生就支持负载均衡。假设我们除了本地的8080端口还在同一台机器的8088端口启动了另一个后端服务实例或者另一台服务器。我们可以这样配置# 在http块内定义一个上游服务器组名字叫webservers upstream webservers { server 127.0.0.1:8080 weight10; # 服务器1权重10 server 127.0.0.1:8088 weight5; # 服务器2权重5 # 还可以配置更多策略如ip_hash、fair等 } server { listen 80; server_name localhost; location / { root html; index index.html index.htm; } location /api/ { # 将代理地址指向上面定义的上游服务器组 proxy_pass http://webservers/admin/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }这个upstream块定义了一个叫webservers的服务器集群里面有两个成员。weight代表权重Nginx会按权重比例这里是10:5即2:1把请求分发到这两台服务器上。比如来了15个请求大概会有10个打到80805个打到8088。这是一种非常简单的加权轮询策略。Nginx还支持其他策略比如ip_hash根据客户端IP哈希固定分配到某一台适合会话保持、least_conn分配给当前连接数最少的服务器等。负载均衡的配置让我们的后端服务具备了横向扩展的能力应对流量压力时更加从容。3. 后端安全加固密码加密存储与JWT令牌前后端通了咱们来看看后端登录接口里的一些关键细节。直接存储用户明文密码是开发大忌一旦数据库泄露后果不堪设想。在“苍穹外卖”的EmployeeService的login方法里我们看到使用了Spring提供的DigestUtils.md5DigestAsHex对前端传来的密码进行MD5加密然后与数据库中预先存储的加密密码进行比对。// 对用户登录的密码做md5加密处理后和数据库加密后的密码对比 password DigestUtils.md5DigestAsHex(password.getBytes()); if (!password.equals(employee.getPassword())) { throw new PasswordErrorException(密码错误); }这里用的是MD5但需要提醒大家的是单纯的MD5现在已不够安全因为它速度快容易遭到彩虹表攻击。在实际生产环境中更推荐使用加盐的哈希算法比如BCrypt、PBKDF2或Argon2。Spring Security 就内置了对 BCrypt 的完美支持它会自动生成一个随机的“盐”salt并混入密码中进行哈希即使两个用户密码相同加密后的结果也完全不同安全性大大提升。我建议新项目可以直接上 BCrypt。登录成功后我们生成一个JWT令牌返回给前端。JWTJSON Web Token是一种紧凑的、自包含的令牌格式。你看到代码里用JwtUtil.createJWT方法把用户ID等信息claims用秘钥加密后生成一个字符串令牌。前端拿到这个令牌后在后续的请求中都要在HTTP请求头里带上它通常是Authorization: Bearer token。后端通过拦截器验证这个令牌的合法性和有效性从而识别用户身份。这种方式实现了无状态的认证非常适合前后端分离和分布式系统。4. 接口文档自动化Swagger/Knife4j实战详解接下来是提升团队协作效率的重头戏——自动化接口文档。我们选择Knife4j它是Swagger的增强版界面更友好功能更强大。首先在项目的pom.xml里引入依赖注意Spring Boot版本兼容性dependency groupIdcom.github.xiaoymin/groupId artifactIdknife4j-openapi2-spring-boot-starter/artifactId version4.4.0/version /dependency然后我们需要创建一个配置类来启用Knife4j。通常我会在config包下建一个WebMvcConfiguration类。这个配置类主要干两件事一是配置Swagger的Docket Bean告诉它要扫描哪些包生成文档二是设置静态资源映射让Knife4j的UI界面能正常访问。Configuration Slf4j public class WebMvcConfiguration extends WebMvcConfigurationSupport { Bean public Docket docket() { // 创建文档信息 ApiInfo apiInfo new ApiInfoBuilder() .title(苍穹外卖项目接口文档) .version(2.0) .description(这是一个详细的后端API文档由Knife4j自动生成) .build(); Docket docket new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo) // 指定文档信息 .select() // 指定要扫描的控制器包路径这是关键 .apis(RequestHandlerSelectors.basePackage(com.sky.controller)) .paths(PathSelectors.any()) .build(); return docket; } Override protected void addResourceHandlers(ResourceHandlerRegistry registry) { log.info(开始设置静态资源映射...); // 映射Knife4j的静态资源这样才能访问/doc.html registry.addResourceHandler(/doc.html) .addResourceLocations(classpath:/META-INF/resources/); registry.addResourceHandler(/webjars/**) .addResourceLocations(classpath:/META-INF/resources/webjars/); } }配置完成后启动你的Spring Boot应用。然后打开浏览器访问http://localhost:8080/doc.html注意这里是直接访问后端服务的8080端口不是Nginx的80端口。一个功能强大、界面美观的API文档页面就展现在你眼前了。所有在com.sky.controller包下的控制器及其方法都会被自动扫描展示。你可以点开任何一个接口查看它的请求路径、参数说明、甚至直接在线填写参数发起测试非常方便。4.1 用好Swagger注解让文档更清晰自动生成虽然方便但有些细节还需要我们通过注解来完善。Swagger提供了一系列注解让文档可读性更强。这里我结合“苍穹外卖”的登录接口给你讲讲最常用的几个RestController RequestMapping(/admin/employee) Api(tags 员工管理相关接口) // Api用在控制器类上给整个控制器一个分类标签 Slf4j public class EmployeeController { PostMapping(/login) ApiOperation(value 员工登录) // ApiOperation用在具体接口方法上描述接口用途 public ResultEmployeeLoginVO login( RequestBody ApiParam(value 员工登录DTO, required true) // ApiParam描述单个参数 EmployeeLoginDTO employeeLoginDTO) { // ... 业务逻辑 } } // 在DTO/VO类上使用 Data ApiModel(value 员工登录DTO, description 员工登录时传递的数据模型) // ApiModel描述数据模型 public class EmployeeLoginDTO { ApiModelProperty(value 用户名, required true, example admin) // ApiModelProperty描述模型属性 private String username; ApiModelProperty(value 密码, required true, example 123456) private String password; }加了这些注解后重启服务再看文档你会发现接口的描述、参数的名称和示例值都一目了然。前端开发同学再也不用猜这个字段是干嘛的、该传什么格式了。这能极大减少沟通成本把联调期的“撕逼”时间用来喝咖啡不香吗4.2 Swagger与Yapi定位不同相辅相成可能有同学会问有了Swagger我们还需要Yapi这样的接口管理平台吗我的经验是两者定位不同可以配合使用。Yapi更像是一个在项目设计阶段和团队协作阶段使用的“接口仓库”和“管理工具”。产品经理或架构师可以在Yapi上先定义好接口规范URL、参数、响应形成一个契约。前后端开发都依据这个契约并行开发。Yapi还支持Mock数据、自动化测试、版本管理等功能非常适合团队协作和项目管理。而SwaggerKnife4j则是开发阶段的“即时文档”和“测试工具”。它的最大优势是与代码强绑定你写代码的同时就把文档写了保证文档永远和代码同步。它的主要使用者是后端开发自己用于自测和前端开发用于查看最新接口细节和快速调试。所以一个比较理想的流程是前期在Yapi定好接口契约开发时用Swagger实现和测试后期维护时Swagger的实时性优势就体现出来了。它们不是替代关系而是上下游的互补关系。5. 避坑指南与最佳实践搞技术这么多年我深知“跑通”只是第一步要“跑得稳”还得注意很多细节。这里分享几个在配置Nginx和Swagger时容易踩的坑以及我总结的一些最佳实践。Nginx配置的坑路径拼接问题proxy_pass指令的结尾有没有斜杠/行为大不相同。proxy_pass http://backend/admin/;会把/api/xxx替换成/admin/xxx。而proxy_pass http://backend/admin;没有结尾斜杠则会拼接成/adminxxx导致404。我建议统一在目标地址后加上斜杠。配置不生效修改了nginx.conf后一定要重启或重载Nginx。命令行下用nginx -s reload是最优雅的方式。如果重启失败可以用nginx -t先测试配置文件语法是否正确。静态资源访问404如果你的Vue项目里用了路由的history模式直接刷新非首页的页面可能会404。这是因为Nginx把该路径当成了后端接口或文件路径。需要在Nginx的location /块里添加一个try_files指令try_files $uri $uri/ /index.html;它的意思是先找真实文件找不到就返回index.html让前端路由自己去处理。Swagger的坑与最佳实践生产环境一定要关闭Swagger界面会暴露你所有的接口信息这在生产环境是极大的安全风险。务必通过Profile如spring.profiles.activeprod来控制只在开发环境启用Swagger配置。可以通过条件注解Profile({dev, test})来实现。接口分组大型项目控制器很多所有接口堆在一个页面里很难找。Knife4j支持分组Group。你可以创建多个Docket Bean用groupName()方法区分分别扫描不同的包这样文档结构更清晰。统一响应体包装很多项目会用ResultT这种统一响应格式。为了让Swagger能正确识别你需要在Docket里配置globalResponseMessage或者更推荐使用ApiResponses注解在接口上明确声明。否则Swagger可能会认为你的接口直接返回EmployeeLoginVO对象而不是包装后的ResultEmployeeLoginVO。处理认证像我们项目用了JWT怎么在Swagger页面上测试需要认证的接口呢Knife4j提供了“全局参数”功能。在文档页面的右上角通常有一个“文档管理”或“全局参数设置”你可以在那里添加一个名为Authorization值为Bearer your_jwt_token的Header参数。这样之后发起的每个请求都会自动带上这个令牌。最后关于密码加密再啰嗦一句。MD5在当下已非首选如果项目刚开始强烈建议在数据库密码字段存储时就使用BCryptPasswordEncoder这类强哈希算法。Spring Security内置了用起来非常方便。安全无小事从项目第一天就要重视起来。配置完这些你的“苍穹外卖”项目就拥有了一个稳健的通信基础Nginx反向代理与负载均衡和一个高效的团队协作工具Swagger自动化文档。这套组合拳不仅能用于这个项目几乎可以套用到任何Spring Boot Vue的前后端分离项目中。下次启动新项目这些配置就是你的标准起手式了。如果过程中遇到问题多看看日志Nginx的error.log和Spring Boot的控制台输出里面藏着绝大部分问题的答案。