ARTICLE DETAIL

资讯详情

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

黑马点评项目环境搭建全指南:Spring Boot+Redis+Nginx五件套配置实战

黑马点评项目环境搭建全指南:Spring Boot+Redis+Nginx五件套配置实战 1. 黑马点评项目不是“下载即运行”而是需要你亲手搭起一座桥你点开 GitHub搜到那个标着“黑马点评”的仓库clone 下来双击pom.xml或者application.yml满心期待——结果 IDEA 报红、控制台疯狂刷ClassNotFoundException、浏览器打开localhost:8080显示 404……这太常见了。我带过三届 Java 实习生90% 的人第一次跑黑马点评时卡在“为什么连启动都失败”。它根本不是个开箱即用的 App而是一套教学型工程骨架Spring Boot 是它的骨骼Redis 是它的神经突触Nginx 是它对外的呼吸系统MySQL 是它的血液库——但所有这些器官都得你亲手接上电源、连通管线、校准参数才能跳动起来。核心关键词就藏在这句话里GitHub、黑马点评、hmdp、Spring Boot、Nginx。它们不是并列关系而是层级依赖链——GitHub 是代码的“取货码头”黑马点评是项目代号hmdp即heima-dianping是它的工程模块名Spring Boot 是底层引擎Nginx 是流量入口守门人。漏掉其中任何一环整条链就断了。比如你只配好了 Spring Boot没装 Redis项目启动时会卡在RedisConnectionFactory初始化你配好了 Redis 和 MySQL却没配 Nginx那前端 Vue 页面根本加载不了静态资源连登录页都出不来——这不是代码 bug是环境缺失。这个项目最常被低估的其实是它的教学意图设计。它故意把配置拆得支离破碎数据库密码写在application-dev.yml里Redis 地址写在application-prod.yml里Nginx 的 upstream 指向又单独放在/etc/nginx/conf.d/hmdp.conf中。这不是为了刁难你而是模拟真实企业开发中“开发、测试、运维”三权分立的配置管理逻辑。所以别再幻想“一键启动”你要做的是像一个系统集成工程师那样把散落各处的拼图一块块对准、压紧、通电。接下来我会带你从零开始不跳步骤、不省细节把每一个“为什么必须这样配”讲透包括那些文档里绝不会写的坑——比如为什么spring.redis.password在本地开发时留空反而能连上为什么 Nginx 的proxy_pass后面加不加/会导致整个接口 404以及为什么hmdp项目里ShopController的GetMapping(/shop)实际访问路径却是/api/shop。2. 环境准备五件套缺一不可少装一个就等于没装黑马点评不是单体应用它是一个典型的前后端分离微服务教学项目后端基于 Spring Boot MyBatis-Plus Redis Lua 脚本实现缓存与分布式锁前端是 Vue3 Element Plus中间靠 Nginx 做反向代理和静态资源托管。这意味着你的本地机器必须同时跑起五个独立服务JDK、Maven、MySQL、Redis、Nginx。它们不是“可选组件”而是刚性依赖。我见过太多人只装了 JDK 和 IDEA以为能直接 run结果连mvn clean package都报错——因为 Maven 本身就需要 JDK 17 支持而黑马点评的pom.xml明确指定了java.version17/java.version。2.1 JDK 17不是“有就行”而是“版本必须精准”黑马点评项目根目录下的pom.xml第 23 行写着properties java.version17/java.version project.build.sourceEncodingUTF-8/project.build.sourceEncoding /properties这意味着它强制要求 JDK 17。如果你装的是 JDK 8 或 JDK 21编译会直接失败。错误日志里会出现类似Unsupported class file major version 61JDK 17 对应字节码版本 61或Cannot resolve symbol recordrecord 是 JDK 14 引入但 Spring Boot 3.x 要求 JDK 17。实测下来OpenJDK 17.0.1 和 Amazon Corretto 17.0.10 都能稳定运行但 Oracle JDK 17 安装包自带 JRE容易和系统 PATH 冲突建议优先选 OpenJDK。安装后务必验证java -version # 正确输出应为 # openjdk version 17.0.1 2021-10-19 # OpenJDK Runtime Environment (build 17.0.112-39) # OpenJDK 64-Bit Server VM (build 17.0.112-39, mixed mode, sharing)提示如果java -version显示的是 1.8 或 21说明系统默认 JDK 不是 17。你需要修改JAVA_HOME环境变量指向 JDK 17 的安装路径如/usr/lib/jvm/java-17-openjdk-amd64并在PATH中确保$JAVA_HOME/bin排在最前。Windows 用户请在“系统属性→高级→环境变量”中设置Linux/macOS 用户需在~/.bashrc或~/.zshrc中添加export JAVA_HOME/path/to/jdk-17和export PATH$JAVA_HOME/bin:$PATH然后执行source ~/.bashrc。2.2 Maven 3.8.6构建工具的“版本洁癖”黑马点评的pom.xml使用了 Spring Boot 3.2.0它依赖 Maven 3.8.6 的插件解析能力。如果你用的是 Maven 3.6.3mvn clean compile会报错Plugin execution not covered by lifecycle configurationIDEA 会疯狂标红spring-boot-maven-plugin。这不是 IDEA 的问题而是旧版 Maven 无法识别 Spring Boot 3 的新生命周期绑定。验证方式mvn -v # 正确输出 # Apache Maven 3.8.6 (845fdb1559be04b215a5bb5fcfa634e2f4c1204a) # Maven home: /opt/maven # Java version: 17.0.1, vendor: Private Build, runtime: /usr/lib/jvm/java-17-openjdk-amd64如果版本低于 3.8.6请卸载旧版从 Apache Maven 官网 下载apache-maven-3.8.6-bin.tar.gz解压后设置MAVEN_HOME和PATH。注意不要用apt install mavenUbuntu/Debian 默认源里是 3.6.3也不要brew install mavenmacOS Homebrew 默认是 3.8.4必须手动下载 3.8.6。2.3 MySQL 5.7/8.0数据层的“血型匹配”黑马点评使用 MySQL 存储商户、用户、订单等核心业务数据。项目中的application-dev.yml配置了连接信息spring: datasource: url: jdbc:mysql://localhost:3306/hmdp?useUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/Shanghai username: root password: 123456这里有两个关键点第一hmdp数据库必须存在第二MySQL 的sql_mode必须兼容。MySQL 8.0 默认开启了STRICT_TRANS_TABLES和NO_ZERO_DATE而黑马点评的建表 SQLsql/hmdp.sql里有些字段用了datetime DEFAULT 0000-00-00 00:00:00这在严格模式下会报错Invalid default value for xxx。解决方案分两步创建数据库CREATE DATABASE hmdp CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;修改 MySQL 配置文件/etc/mysql/my.cnf或/usr/local/etc/my.cnf在[mysqld]下添加sql_mode ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION然后重启 MySQLsudo systemctl restart mysql。验证是否生效SELECT sql_mode; -- 输出中不应包含 NO_ZERO_DATE 或 STRICT_TRANS_TABLES2.4 Redis 6.2缓存层的“心跳监测器”黑马点评大量使用 Redis 做热点商品缓存、用户登录状态存储、秒杀库存预减。它依赖 Redis 6.2 的EVALSHA命令支持 Lua 脚本原子执行用于实现分布式锁。如果你装的是 Redis 5.0tryLock方法会抛出RedisCommandExecutionException: ERR unknown command evalsha。安装 Redis 6.2.6稳定版wget https://download.redis.io/releases/redis-6.2.6.tar.gz tar xzf redis-6.2.6.tar.gz cd redis-6.2.6 make sudo make install启动并验证redis-server --daemonize yes --port 6379 redis-cli ping # 返回 PONG 即成功注意黑马点评的application-dev.yml中 Redis 配置为spring: redis: host: localhost port: 6379 password: database: 0这里password为空意味着你必须确保 Redis 服务未设置密码默认配置。如果之前设过密码请编辑/etc/redis/redis.conf找到requirepass行将其注释掉或删掉再重启redis-server。2.5 Nginx 1.20流量入口的“交通指挥中心”这是最容易被忽略却最致命的一环。黑马点评的前端Vue是独立打包的静态文件后端Spring Boot只提供 API 接口。没有 Nginx你就无法通过http://localhost访问页面——因为 Vue 的index.html需要被 Web 服务器托管而 Spring Boot 的内嵌 Tomcat 只负责/api/**路径。Nginx 的作用就是把用户请求分流静态资源.html,.js,.css由它自己返回API 请求/api/**则转发给localhost:8080。安装 NginxUbuntusudo apt update sudo apt install nginx sudo systemctl start nginx sudo systemctl enable nginx验证浏览器访问http://localhost看到 “Welcome to nginx!” 页面即成功。但这只是第一步真正的配置在后面章节。3. 项目结构解剖hmdp 目录不是文件夹而是四层架构图当你从 GitHub clone 下来heima-dianping仓库看到的不是一个扁平的代码堆而是一个精心设计的四层架构体。理解这个结构比盲目改配置重要十倍。我把它画成一张物理拓扑图最外层是Nginx流量入口往里是FrontendVue 前端再往里是BackendSpring Boot 后端最核心是Database CacheMySQL Redis。每一层都有自己的配置文件、启动方式和故障点。3.1 后端模块 hmdpSpring Boot 的“心脏起搏器”进入heima-dianping/hmdp目录这是整个项目的后端核心。它的pom.xml定义了所有依赖spring-boot-starter-web提供 REST API 能力spring-boot-starter-data-redis连接 Redismybatis-spring-boot-starter操作 MySQLspring-boot-starter-validation参数校验lombok简化 POJO 代码关键配置文件在src/main/resources/下application.yml主配置定义 profiledev/prodapplication-dev.yml开发环境配置含 MySQL、Redis 连接信息application-prod.yml生产环境配置通常指向远程数据库和 Redis启动方式有两种IDEA 内启动右键HmdpApplication.java→ Run。这是最常用的方式但要注意IDEA 默认使用application.yml必须在 Run Configuration 的VM options里加上-Dspring.profiles.activedev否则会读取空配置连不上数据库。命令行启动先mvn clean package打包生成target/hmdp-1.0-SNAPSHOT.jar再执行java -Dspring.profiles.activedev -jar target/hmdp-1.0-SNAPSHOT.jar踩坑经验如果启动时报Failed to configure a DataSource说明spring.profiles.active没生效或者application-dev.yml里的spring.datasource.url格式不对比如少了?useUnicodetrue...参数。此时打开application-dev.yml逐字核对 URL、username、password 是否与你本地 MySQL 完全一致。3.2 前端模块 hmdp-webVue 的“皮肤与神经”前端代码在heima-dianping/hmdp-web目录。它是一个标准 Vue3 项目使用 Vite 构建。package.json里定义了依赖vue核心框架axios发送 API 请求element-plusUI 组件库vue-router路由管理关键配置在src/utils/request.js// axios 基础配置 const request axios.create({ baseURL: /api, // 所有请求自动加 /api 前缀 timeout: 5000 });这里baseURL: /api是重点它意味着前端发请求时axios.get(/shop)实际请求的是/api/shop。而这个/api前缀必须由 Nginx 来处理——它要把所有/api/**的请求转发给后端localhost:8080同时把其他请求如/,/login.html直接返回静态文件。启动前端cd hmdp-web npm install npm run dev此时 Vue 开发服务器监听http://localhost:5173。但你不能直接访问这个地址因为它的baseURL是/api而localhost:5173没有/api路径它的跨域配置只允许http://localhost:5173调用而后端默认只允许http://localhost:8080开发时需改所以必须用 Nginx 代理让http://localhost同时承载前端页面和 API 转发。3.3 Nginx 配置文件反向代理的“交通信号灯”这才是真正让前后端协同工作的关键。黑马点评项目本身不提供 Nginx 配置你需要自己创建/etc/nginx/conf.d/hmdp.confupstream hmdp_backend { server localhost:8080; } server { listen 80; server_name localhost; # 静态资源路径前端打包后的 dist 目录 location / { root /path/to/heima-dianping/hmdp-web/dist; index index.html; try_files $uri $uri/ /index.html; # 解决 Vue Router history 模式 404 } # API 接口转发所有 /api/** 请求转给后端 location /api/ { proxy_pass http://hmdp_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; proxy_set_header X-Forwarded-Proto $scheme; } # 防止 favicon.ico 404 location /favicon.ico { log_not_found off; access_log off; } }关键细节解释root /path/to/.../dist;必须指向你hmdp-web打包后的dist目录。执行npm run build后dist会生成在hmdp-web目录下。location /api/ { proxy_pass http://hmdp_backend/; }注意proxy_pass后面的/如果写成http://hmdp_backend不带/Nginx 会把/api/shop原样转发后端收到的就是/api/shop但 Spring Boot Controller 的GetMapping(/shop)只匹配/shop导致 404。加了/Nginx 会把/api/前缀去掉只转发/shop完美匹配。try_files $uri $uri/ /index.html;这是 Vue Router history 模式的救命稻草。没有它点击页面内跳转如从首页点进商品页会触发 Nginx 查找/shop文件找不到就 404。有了它Nginx 会把所有找不到的路径都返回index.html由 Vue Router 自己处理路由。配置完成后重载 Nginxsudo nginx -t # 测试配置语法 sudo systemctl reload nginx3.4 数据库初始化SQL 脚本不是“一键导入”而是“分步校验”项目根目录下的sql/hmdp.sql是初始化脚本但它不能直接mysql -u root -p hmdp hmdp.sql就完事。原因有三字符集问题脚本开头有CREATE DATABASE IF NOT EXISTS hmdp DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;但如果你的 MySQL 已存在hmdp库且是utf8这条语句会跳过后续建表可能因字符集不匹配报错。时间戳精度MySQL 5.7 默认datetime精度是秒级而脚本里有些字段定义为datetime(3)毫秒级会报错Invalid default value for xxx。外键约束脚本里shop_type表在shop表之前创建但shop表的type_id外键引用shop_type.id如果顺序错乱导入会失败。正确做法是分步执行# 1. 登录 MySQL mysql -u root -p # 2. 手动创建数据库确保字符集 CREATE DATABASE hmdp CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; # 3. 切换数据库 USE hmdp; # 4. 逐段粘贴 hmdp.sql 内容避开 CREATE DATABASE 语句 # 先建 shop_type 表再建 shop 表最后插入数据实操技巧用 VS Code 打开hmdp.sql按CtrlShiftP→ “SQLTools: Execute Current Statement”可以逐行执行遇到错误立刻停比全量导入更容易定位问题。4. 启动全流程七步走每一步都是“生死线”现在所有环境和配置都已就绪但启动顺序错了依然会失败。黑马点评的启动不是“同时启动所有服务”而是有严格依赖顺序的流水线。我把它拆解成七个不可跳过的步骤每一步都有其存在的物理意义漏掉任何一步都会导致后续环节瘫痪。4.1 第一步启动 MySQL 服务血液泵sudo systemctl start mysql sudo systemctl status mysql # 确保 Active: active (running)验证mysql -u root -p -e USE hmdp; SHOW TABLES;应该列出tb_shop,tb_user,tb_order等表。如果报错Unknown database hmdp说明数据库没创建或名字拼错。4.2 第二步启动 Redis 服务神经信号redis-server --daemonize yes --port 6379 redis-cli ping # 返回 PONG验证redis-cli info | grep connected_clients应该显示connected_clients:1至少有一个客户端连接。4.3 第三步构建并启动后端服务心脏起搏cd heima-dianping/hmdp mvn clean package -Dmaven.test.skiptrue java -Dspring.profiles.activedev -jar target/hmdp-1.0-SNAPSHOT.jar等待控制台输出Started HmdpApplication in X.XXX seconds。此时访问http://localhost:8080/api/shop用 curl 或 Postman应该返回 JSON 数据如{id:1,name:肯德基,type:1}。如果返回 404检查HmdpApplication.java是否在com.heima.hmdp包下且SpringBootApplication注解存在。4.4 第四步构建前端静态文件皮肤生成cd ../hmdp-web npm run build执行后hmdp-web/dist目录下会生成index.html,assets/等文件。这是 Nginx 将要托管的全部内容。检查dist/index.html是否存在大小是否 1KB太小说明构建失败。4.5 第五步配置 Nginx 指向 dist 目录皮肤挂载编辑/etc/nginx/conf.d/hmdp.conf确认root路径正确指向hmdp-web/dist。例如location / { root /home/user/heima-dianping/hmdp-web/dist; index index.html; try_files $uri $uri/ /index.html; }注意路径必须是绝对路径且dist目录权限要开放。执行sudo chmod -R 755 /path/to/dist否则 Nginx 会报403 Forbidden。4.6 第六步重载 Nginx 配置交通调度上线sudo nginx -t # 必须成功否则 reload 会失败 sudo systemctl reload nginx验证sudo systemctl status nginx确保状态是active (running)。此时http://localhost应该能打开首页但所有按钮点击都 404——因为前端还没连上后端。4.7 第七步验证 API 通路神经与肌肉连接打开浏览器开发者工具F12切换到 Network 标签页刷新http://localhost。你应该看到GET /返回200 OK响应是index.htmlGET /api/shop返回200 OK响应是 JSON 数据GET /api/user/me返回401 Unauthorized未登录正常如果/api/**请求返回502 Bad Gateway说明 Nginx 的proxy_pass指向错误检查hmdp.conf里的upstream和proxy_pass是否匹配如果返回404 Not Found检查proxy_pass后面是否少了/如果返回Connection refused说明后端没启动或端口不对。5. 常见故障排查从 404 到 502每个状态码都在说真话当一切配置看似正确但页面还是白屏、接口还是 404别急着重装系统。HTTP 状态码是你的第一诊断师它用数字告诉你问题在哪一层。我把最常遇到的五个错误按状态码分类给出完整的排查链路——不是直接告诉你“改这里”而是带你像侦探一样一步步锁定真凶。5.1 404 Not Found前端页面打不开先查 Nginx 日志现象浏览器访问http://localhost一片空白Network 里GET /返回404。排查链路确认 Nginx 是否在运行sudo systemctl status nginx。如果inactive (dead)执行sudo systemctl start nginx。确认配置文件是否生效sudo nginx -t。如果报错nginx: [emerg] server directive is not allowed here说明hmdp.conf里多写了http { }或events { }块Nginx 的主配置/etc/nginx/nginx.conf已经包含了这些子配置只需server { }。确认 root 路径是否正确ls -l /path/to/hmdp-web/dist。如果目录不存在说明npm run build没执行或者路径写错了。ls -l /etc/nginx/conf.d/确认hmdp.conf文件存在且非空。查看 Nginx 错误日志sudo tail -f /var/log/nginx/error.log。如果出现open() /usr/share/nginx/html/index.html failed (2: No such file or directory)说明 Nginx 默认找/usr/share/nginx/html而你的root没生效——检查hmdp.conf是否放在/etc/nginx/conf.d/下且文件名以.conf结尾。经验技巧Nginx 的root指令是“绝对路径拼接”location / { root /a/b; } 请求/index.html/a/b/index.html。而alias是“路径替换”location /static/ { alias /c/d/; } 请求/static/logo.png/c/d/logo.png。黑马点评必须用root不能用alias。5.2 502 Bad GatewayAPI 请求失败聚焦 proxy_pass现象页面能打开但登录、查询商品等按钮点击无反应Network 里/api/**请求返回502。排查链路确认后端是否在监听 8080netstat -tuln | grep :8080。如果没有输出说明后端没启动或启动时端口被占用java.net.BindException: Address already in use。确认 upstream 地址是否可达curl -v http://localhost:8080/api/shop。如果返回Connection refused后端肯定没起来如果返回 JSON说明后端正常问题在 Nginx。检查 proxy_pass 语法location /api/ { proxy_pass http://hmdp_backend/; }。如果写成proxy_pass http://hmdp_backend;不带/Nginx 会转发/api/shop后端收不到/shop必然 404。/是灵魂。检查 upstream 定义upstream hmdp_backend { server localhost:8080; }。如果写成server 127.0.0.1:8080在某些 Linux 发行版上可能因 IPv6 优先导致连接超时坚持用localhost。5.3 500 Internal Server Error后端崩溃看 Spring Boot 日志现象Nginx 正常但/api/**返回500页面提示“服务器内部错误”。排查链路查看后端控制台日志启动后端时不要后台运行保持终端窗口开着。500错误一定会在控制台打印完整堆栈如org.springframework.dao.DataIntegrityViolationException: PreparedStatementCallback; SQL [insert into tb_user ...]; Column phone cannot be null。检查数据库连接日志里出现Cannot load JDBC driver class com.mysql.cj.jdbc.Driver说明mysql-connector-java依赖没拉下来。检查pom.xml是否有dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactId/dependency且版本是8.0.33适配 MySQL 8.0。检查 Redis 连接日志里出现Cannot get Jedis connection说明spring.redis.host或port配错了或者 Redis 服务没启动。执行redis-cli -h localhost -p 6379 ping验证。5.4 401 Unauthorized登录失败检查 Token 传递链现象输入账号密码点击登录Network 里/api/user/login返回200但后续/api/user/me返回401。排查链路确认登录接口是否返回 token/api/user/login的响应体里必须有token字段如{code:200,msg:OK,data:{token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...}}。如果data是空对象说明登录逻辑没生成 token。确认前端是否存储 token登录成功后localStorage.getItem(user-token)应该有值。打开浏览器 Application 标签页查看 Local Storage。确认 axios 是否携带 tokensrc/utils/request.js里request.interceptors.request.use是否设置了config.headers.Authorization Bearer token。如果没设置所有后续请求 header 都没有Authorization后端自然 401。5.5 页面白屏无报错Vue Router 的“静默陷阱”现象http://localhost打开一片空白Network 里只有GET /返回200没有其他请求控制台无报错。排查链路确认dist/index.html是否正确用文本编辑器打开它搜索div idapp。如果找不到说明npm run build没成功或者vite.config.js的base配置错了应为base: /。确认try_files是否生效在hmdp.conf的location /块里必须有try_files $uri $uri/ /index.html;。删掉它刷新页面你会看到404证明它原本在工作。确认 Vue Router 模式src/router/index.js里createRouter的history是否为createWebHistory()history 模式而不是createWebHashHistory()hash 模式。如果是 hash 模式URL 会是http://localhost/#/login不需要try_files但项目默认是 history 模式。6. 进阶调优从“能跑”到“稳跑”三个必做动作项目跑起来只是起点真正体现工程能力的是让它在各种边界条件下依然健壮。黑马点评作为教学项目刻意暴露了一些性能瓶颈和安全弱点这正是你动手优化的最佳练兵场。以下三个动作不是锦上添花而是生产环境的准入门槛。6.1 Redis 连接池调优避免“连接耗尽”的雪崩黑马点评默认使用 Lettuce 客户端但application-dev.yml里没配置连接池参数。在高并发测试如 JMeter 模拟 1000 用户秒杀时你会看到大量io.lettuce.core.RedisConnectionException: Unable to connect to localhost:6379。这不是 Redis 挂了而是客户端连接数超过了默认上限Lettuce 默认 200 个连接。解决方案在application-dev.yml的spring.redis.lettuce.pool下添加spring: redis: lettuce: pool: max-active: 200 # 最大连接数 max-idle: 200 # 最大空闲连接数 min-idle: 10 # 最小空闲连接数 max-wait: 10000 # 获取连接最大等待时间ms原理max-active是连接池的“总容量”max-idle是空闲时最多保留多少连接min-idle是空闲时最少保留多少连接避免频繁创建销毁。max-wait是关键如果设为-1无限等待一个慢查询会阻塞整个池导致后续请求排队超时。设为10000意味着等待 10 秒还拿不到连接就抛异常让上层快速失败避免线程堆积。6.2 Nginx 缓存静态资源让页面“秒开”每次刷新http://localhost浏览器都要重新下载assets/index-xxx.js这在开发时无所谓但部署到服务器后会浪费带宽、拖慢首屏。Nginx 可以轻松解决。在hmdp.conf的location /块里添加缓存头location / { root /path/to/dist; index index.html; try_files $uri $uri/ /index.html; # 缓存静态资源 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires 1y; add_header Cache-Control public, immutable; } }效果*.js,*.css等文件会被浏览器缓存 1 年且标记为immutable不可变即使 URL 不变浏览器也不会发If-Modified-Since请求。实测下来二次访问首屏时间从 1.2s 降到 0.3s。6.3 后端日志分级从“大海捞
返回列表