news 2026/9/18 2:51:54

Spring Boot+Vue容器化部署:Docker镜像构建与Compose一键编排

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring Boot+Vue容器化部署:Docker镜像构建与Compose一键编排

前后端项目部署这件事,说起来就是一套流程,但真自己动手时能把人折腾到怀疑人生。本地启动Spring Boot和后端联调没问题,前端Vue跑在开发服务器里也顺畅,可一旦要把这两货放到一台服务器上,Port占用、路径混乱、环境不一致、数据库又没装,各种问题接踵而至。我接手的一个项目进度管理系统就是这套技术栈,借着Docker把它从头到尾容器化了一遍,之后无论是换服务器还是团队协作,部署效率都提了一个档次。这篇博文打算把整套“Docker部署Spring Boot + Vue项目”的实操过程写透,包括为什么这么拆、每个配置文件怎么来的、踩过的坑也都列出来,适合刚接触容器化部署的Java后端和前端同学参考,如果你已经会docker run跑个nginx,这篇能帮你直接把前后端项目完整落地。

1. 为什么非要用Docker跑这套Spring Boot + Vue项目

1.1 前后端部署的麻烦事

先聊聊我在没有用Docker之前是怎么部署的。服务器上得先装JDK、Nginx、MySQL、Redis,Spring Boot项目用mvn package打出一个jar包,然后用nohup java -jar xxx.jar &挂起来。Vue前端用npm run build生成一个dist目录,把这个目录拷到服务器的某个路径下,再去改Nginx的root指向。听起来不复杂,但真正操作过几轮就发现问题了。

首先是环境不一致。开发电脑上JDK版本是1.8,服务器上却装了17,Spring Boot的某些配置行为直接不一样,jar包明明在本地跑得好好的,服务器上一启动就报错。其次是依赖服务的管理,MySQL要单独装一遍,Redis要单独配密码和持久化,这些中间件版本稍微差一点,项目可能就连接不上。而且一旦要换服务器,这一整套流程又得重来,光是靠文档去还原环境,基本都会漏掉某一步。

Docker出来之后,部署逻辑就变成了“把运行环境和应用本身打个包”。构建产物拿过去直接能跑,服务器只需要有Docker引擎,其余都通过容器隔离。我后来把这套项目容器化之后,最直观的感受是:部署步骤从原来的二十多步压缩到了两条命令,团队成员pull下来也能复现一模一样的环境,环境这个东西终于不是玄学了。

1.2 容器化部署方案选型

在做方案选型的时候,我先想清楚了一个问题:前后端容器到底怎么组织。最粗暴的做法是把Spring Boot的jar包、Vue的dist目录塞进同一个镜像,然后用一个容器全部跑起来。这在demo项目里可行,但生产环境里问题很多,Nginx和Java应用进程混在一起,日志分开看麻烦,想单独扩容前端或后端也没法操作。所以最终我选择的是“前后端分离容器”的组合方式。

另外一个需要考虑的问题是编排工具。方案定下来之后,我的部署结构是:

  • 前端容器:运行Nginx,托管Vue的静态资源,同时做反向代理,把/api前缀的请求转发给后端容器。
  • 后端容器:运行Spring Boot应用,监听8080。
  • 数据库容器:MySQL 8.0,数据目录挂载到宿主机。
  • 缓存容器:Redis,用于项目的Session和缓存数据。

有了清晰的部署目标,接下来就是逐步准备环境、写Dockerfile、写编排文件的过程,下面逐一展开。

2. Docker环境准备与镜像加速(附Windows踩坑)

2.1 安装Docker时的硬件虚拟化检查

先说环境准备。如果服务器是Linux(CentOS 7/Ubuntu 20.04这类),安装Docker本身很顺利,官方脚本或者包管理器都能搞定。但我在Windows开发机上遇到过很典型的坑,就是Docker Desktop启动时报virtualization support wasn't detected。这个问题本质是Windows的硬件虚拟化没有开启,或者WSL2没有正确安装。

我当时排查的步骤是:先在任务管理器里看“性能”标签下的CPU虚拟化是否显示“已启用”,如果没启用,就得去BIOS里打开Intel VT-x或AMD-V。然后确认Windows功能里的“适用于Linux的Windows子系统”和“虚拟机平台”两个选项都勾上了。如果这些都没问题但还是报错,执行一下wsl --update,再以管理员身份重启Docker Desktop。我把这个踩坑过程写出来,是因为很多人在这一步就被劝退了,其实多数情况就是BIOS里一个开关的事。

Linux服务器上装好Docker后,建议顺手把当前用户加入docker用户组,避免每次执行docker命令都要加sudo

sudo usermod -aG docker $USER newgrp docker

2.2 配置镜像加速和基础网络

因为网络环境的原因,直接从Docker Hub拉取镜像有时会很慢,这时候需要配置镜像加速器。Linux上编辑/etc/docker/daemon.json,Docker Desktop则是在Settings -> Docker Engine里改配置。我用的是这样一个基础配置:

{ "registry-mirrors": [ "https://docker.m.daocloud.io", "https://dockerproxy.com", "https://hub-mirror.c.163.com" ], "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } }

这里多提一句日志配置,很多人会忽略。Spring Boot应用在生产环境日志量很大,如果不管控Docker日志大小,时间长了会把磁盘写满。json-file配合max-sizemax-file,能把一个容器的日志限制在30MB左右,这个配置我在多个项目里验证过,能避免不少半夜被磁盘告警吵醒的情况。

2.3 基础镜像的选择

Docker镜像体积和构建效率直接相关。后端我一开始图省事,直接用了java:8这种大而全的镜像,构建是简单,但镜像体积动辄几百MB,推送到私有仓库也慢。后面换成了多阶段构建,用maven:3.8-openjdk-8做构建阶段,运行阶段用openjdk:8-jre-alpine。前端也是同理,node:16-alpine用来构建,nginx:alpine用来运行,这样可以尽量保证镜像精简。

基础镜像的选择还要注意一点:不同镜像的时区、字符集不一样。比如alpine系列镜像默认没有配置时区,如果Spring Boot应用在日志里要打印本地时间,需要在Dockerfile里主动装tzdata并设置Asia/Shanghai,这个我在后面写后端Dockerfile时会专门演示。

3. 前端Vue项目的镜像制作:别只把dist丢进nginx

3.1 前端Dockerfile的多阶段构建

Vue项目构建镜像,核心思路就是先把源码build成静态文件,再用Nginx来托管。写Dockerfile之前,我在项目根目录创建了一个.dockerignore文件,把node_modulesdist这些目录排除掉,否则构建上下文会非常大,而且容易把本地的依赖带进镜像,造成不可预期的问题。

node_modules dist .git .DS_Store

然后前端Dockerfile我这样写的:

# 构建阶段 FROM node:16-alpine AS build-stage WORKDIR /app COPY package*.json ./ RUN npm install --registry=https://registry.npmmirror.com COPY . . RUN npm run build # 运行阶段 FROM nginx:alpine AS production-stage COPY --from=build-stage /app/dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]

这里有个细节需要注意:COPY package*.json ./之后先执行npm install,然后再COPY . .。这样做可以利用Docker的层缓存,只要package.json文件没变,镜像构建时npm install这一步会直接用缓存,构建速度能快很多。我刚接触Docker时习惯把整个项目拷贝进去再npm install,每次改一行代码都要重新下载一遍node_modules,那叫一个难受。

3.2 Nginx配置:history路由、反向代理和m3u8播放

前端镜像的核心不只是静态文件,Nginx配置才是重头戏。我用的配置如下:

server { listen 80; server_name localhost; gzip on; gzip_min_length 1k; gzip_comp_level 5; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml; root /usr/share/nginx/html; index index.html; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://backend:8080/api/; 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; } location /stream/ { proxy_pass http://backend:8080/stream/; proxy_set_header Host $host; proxy_buffering off; } }

这里有必要逐条解释一下。第一,Vue项目用了vue-router的history模式后,路径不再是#/xxx,而是/xxx这样的真实路径,前端刷新页面时Nginx会拿着这个路径去磁盘找对应文件,找不到就会404。try_files $uri $uri/ /index.html的意思就是,找不到文件时统一回退到index.html,由前端路由接管。

第二,location /api/反向代理到http://backend:8080/api/,这里的backend是Docker Compose里的服务名,容器之间通过这个内部网络域名互相访问。如果你的后端context-path不是/api,这里可以改写路径,比如proxy_pass不带末尾的/api部分。

第三,我额外加了一个location /stream/,这是因为我项目里有一个Vue播放m3u8视频的功能,m3u8切片文件走的是HTTP流式加载,如果Nginx默认开启了代理缓冲,播放器加载切片会明显变慢或者卡顿。加上proxy_buffering off之后,视频流能更顺畅地边下边播。如果你遇到的是m3u8跨域播放问题,还需要在Nginx里加合适的add_header Access-Control-Allow-Origin *,这个要结合你的业务场景来加,别盲目带上,减少不必要的风险。

3.3 前端镜像的构建与验证

前端Dockerfile和nginx.conf写好后,构建命令是:

docker build -t myapp-vue:1.0.0 .

构建完成后可以先单独跑一下验证静态资源是否正常:

docker run -d -p 8081:80 --name vue-test myapp-vue:1.0.0

然后浏览器访问http://localhost:8081。如果页面能打开,再去开发者工具里看能不能正常访问/api接口。此时因为后端容器还没启动,proxy_pass指向的backend域名是不通的,这属于正常现象,等之后用docker compose把整个环境串起来后再整体验证。

4. 后端Spring Boot项目的镜像制作:JDK版本、时区和瘦身

4.1 后端多阶段构建Dockerfile

Spring Boot项目的镜像,我同样用多阶段构建。先写.dockerignore排除target目录,然后Dockerfile内容如下:

# 构建阶段 FROM maven:3.8-openjdk-8 AS build-stage WORKDIR /app COPY pom.xml . RUN mvn dependency:go-offline -B COPY src ./src RUN mvn package -DskipTests # 运行阶段 FROM openjdk:8-jre-alpine AS production-stage RUN apk add --no-cache tzdata \ && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ && echo "Asia/Shanghai" > /etc/timezone WORKDIR /app COPY --from=build-stage /app/target/*.jar app.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "app.jar"]

这段Dockerfile里有几个细节。第一,构建阶段先COPY pom.xml再执行mvn dependency:go-offline -B,这个命令的作用是先把项目所有依赖下载到本地仓库,之后源码有改动时,只要pom.xml没变,依赖下载这一步就能走缓存。

第二,运行阶段我没有直接用openjdk:8,而是用的openjdk:8-jre-alpine。JRE比JDK小很多,alpine系统也比标准Linux发行版精简不少,最终镜像体积能小一半以上。不过这也会带来一些问题,比如alpine用的musl libc在某些场景下可能和特定的native库不兼容,如果你的项目里用了依赖于glibc的组件,比如某些OCR库、文件处理库,就需要换成openjdk:8-jre-slim这种基于Debian的镜像,这个大家按需选择。

第三,时区问题。Spring Boot默认取容器的系统时区,如果容器是UTC,打印出来的日志时间和我们差8个小时。RUN apk add --no-cache tzdata是安装时区数据,然后用cp把上海的时区文件覆盖到本地的localtime,同时设置timezone环境变量。这样容器里的Java应用打出来的日志时间就是北京时间了。

4.2 JVM参数、优雅停机和健康检查

容器里跑Java应用,JVM参数不能直接照搬物理机。我一般通过环境变量来动态控制JVM内存,开发环境和小项目的配置大概是:

ENTRYPOINT ["java", "-XX:+UseG1GC", "-Xms256m", "-Xmx512m", "-jar", "app.jar"]

但这并不灵活,因为不同环境的服务器配置不一样。更常见的做法是在启动命令里读取环境变量,比如:

ENV JAVA_OPTS="-Xms256m -Xmx512m" ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]

这样的话,在docker-compose.yml里就能通过environment字段灵活覆盖JAVA_OPTS,比如部署到高配置服务器时直接改成-Xms1g -Xmx2g,不需要重新构建镜像。

再说说优雅停机。默认情况下docker stop会先给容器发送SIGTERM信号,Spring Boot收到这个信号后会关闭Spring容器、释放数据库连接池、处理完当前请求再退出。但如果你的应用里有一些非守护线程没有合理设置,进程可能无法自动退出,直到Docker在超时后强制发送SIGKILL。为了增强这个过程的稳定性,我一般会在运行时加入-Xrs或在Spring Boot层面配置graceful shutdown:

server: shutdown: graceful spring: lifecycle: timeout-per-shutdown-phase: 20s

这样在滚动升级时,旧容器能有一段宽限期处理存量请求,不至于一停就丢掉正在处理的业务。

4.3 本地一直正常,容器里连不上数据库

这一步是我多次被问到的经典问题:Spring Boot项目本地启动一切正常,部署到Docker容器里就报Communications link failure或者Access denied。排查思路要先把Docker的网络模型讲清楚。

容器并不是直接跑在宿主机网络里的,它有独立的IP地址。如果Spring Boot配置里的数据库地址写的是localhost:3306,在容器内部这个localhost指的是容器自己,而不是宿主机上的MySQL。所以容器里访问宿主机上的服务,要写host.docker.internal或者用--network=host,而在docker-compose编排里,更规范的做法是用服务名。

我项目里的数据库放在docker-compose里,服务名叫mysql,容器网络是mynetwork,那么Spring Boot的application.yml里就写:

spring: datasource: url: jdbc:mysql://mysql:3306/project_tracker?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false username: root password: your_password

这套配置在本地跑是连不上的,因为本地不存在叫mysql的域名。所以我在本地开发时用的配置是通过spring.profiles.active切换的:本地用local环境,连接localhost;容器里通过环境变量指定prod环境,连接服务名。你可以把连接串里的host提取成环境变量,这样同一个jar包在不同环境下就能灵活切换,既不影响开发,也不影响容器化部署。

5. Docker Compose一键编排整个项目

5.1 docker-compose.yml 完整配置

前面前端镜像和后端镜像都构建好了,但直接用docker run一条条起容器,容器之间的网络、依赖关系、数据卷都很难管理。所以整个项目我用Docker Compose来编排。这里给出一个我实际在用的docker-compose.yml

version: "3.8" services: mysql: image: mysql:8.0 container_name: project-mysql restart: always environment: MYSQL_ROOT_PASSWORD: root123456 MYSQL_DATABASE: project_tracker TZ: Asia/Shanghai command: - --character-set-server=utf8mb4 - --collation-server=utf8mb4_unicode_ci ports: - "3306:3306" volumes: - mysql-data:/var/lib/mysql - ./sql:/docker-entrypoint-initdb.d networks: - mynetwork redis: image: redis:6.2-alpine container_name: project-redis restart: always environment: TZ: Asia/Shanghai ports: - "6379:6379" volumes: - redis-data:/data command: redis-server --appendonly yes --requirepass redis123456 networks: - mynetwork backend: build: context: ./backend dockerfile: Dockerfile container_name: project-backend restart: always environment: SPRING_PROFILES_ACTIVE: prod DB_HOST: mysql DB_PORT: 3306 DB_NAME: project_tracker DB_USERNAME: root DB_PASSWORD: root123456 REDIS_HOST: redis REDIS_PORT: 6379 REDIS_PASSWORD: redis123456 JAVA_OPTS: "-Xms256m -Xmx512m" ports: - "8080:8080" depends_on: - mysql - redis networks: - mynetwork frontend: build: context: ./frontend dockerfile: Dockerfile container_name: project-frontend restart: always ports: - "80:80" depends_on: - backend networks: - mynetwork volumes: mysql-data: redis-data: networks: mynetwork: driver: bridge

这套配置有几个关键设计。第一,所有服务都在同一个自定义网络mynetwork里,这样前端container里的http://backend:8080才能解析到后端容器,后端里的jdbc:mysql://mysql:3306也才能解析到数据库容器。第二,depends_on保证了MySQL和Redis先于后端启动,但注意它只控制启动顺序,并不能保证MySQL完全ready。更严谨的做法是加healthcheck,我在第6节会展开讲。

5.2 MySQL与Redis的持久化细节

容器是无状态的,一旦容器被删除,容器内部写的数据也会跟着消失。所以数据库和Redis的持久化是部署中不能忽略的一环。

我项目里的MySQL数据存放在命名卷mysql-data里,路径映射到容器内的/var/lib/mysql。这样即使容器重建,数据也不会丢。./sql目录映射到/docker-entrypoint-initdb.d,MySQL容器首次启动时会自动执行这个目录下的SQL脚本,我用它来初始化建表和测试数据。需要注意,这个初始化机制只在数据目录为空时生效,如果卷里已经有数据,再改SQL脚本是不会重新执行的。

Redis这边,我通过--appendonly yes开启了AOF持久化,数据文件放在/data,同样挂载了命名卷。生产环境我还设置了--requirepass redis123456来保护Redis,Spring Boot端的连接配置也要同步带上密码,否则会一直报NOAUTH Authentication required

5.3 一键启动、升级和日志查看

编排文件准备好之后,日常操作变得非常简单。首次启动:

docker compose up -d --build

--build会先重新构建有改动的镜像,再启动所有容器。查看运行状态:

docker compose ps

查看指定服务的日志:

docker compose logs -f backend docker compose logs -f frontend

升级某个服务,比如修改了后端代码,只需要:

docker compose build backend docker compose up -d backend

up -d会检测到镜像有更新,自动重建该服务的容器,其他无改动的容器不会受影响。如果不小心把容器搞坏了,想彻底清掉重来:

docker compose down

这个命令会停止并删除所有容器,但只要不添加-v参数,命名卷里的数据都还在,重新up -d后数据依然完整。这个设计让我在多次环境测试时不用担惊受怕,随便折腾,数据始终在。

6. 常见问题排查与个人经验

6.1 高频问题速查表

部署过程中我遇到的高频问题不少,整理成一张表,方便大家对照排查:

现象可能原因排查与解决方法
页面打不开,Nginx报404Vue前端路由是history模式,Nginx没有try_files回退检查nginx.conf是否配置try_files $uri $uri/ /index.html
前端请求/api接口报502后端容器未启动或服务名解析失败docker compose ps查看backend状态,再用docker compose logs backend看日志
后端日志报数据库连接失败application.yml里的数据库地址写错容器内数据库地址应写服务名mysql,不能写localhost
MySQL中文乱码数据库字符集不是utf8mb4在docker-compose的mysql command里显式指定character-set-server=utf8mb4
Spring Boot时间差8小时容器时区为UTC运行阶段镜像安装tzdata,设置Asia/Shanghai
上传文件报413Nginx默认body大小限制在nginx.conf的http或server块加client_max_body_size 50m
Docker日志占满磁盘未限制日志大小在daemon.json中配置log-opts的max-size和max-file
镜像拉取超时网络问题配置registry-mirrors镜像加速地址
前端刷新页面404历史路由模式未配置nginx配置try_files回退到index.html
m3u8视频播放卡顿Nginx代理缓冲导致切片加载延迟针对视频流location添加proxy_buffering off

这里特别说一下413错误。Spring Boot后端默认的spring.servlet.multipart.max-file-size是1MB,Nginx也有一个client_max_body_size默认1MB,两层限制都把上传文件大小卡得很死。调整时不能只改一边,前端请求先经过Nginx,Nginx通过了才会到后端,两边都得改。我在项目里传文件时把Nginx设置成50MB,Spring Boot的multipart也改成对应大小,才把上传问题彻底解决。

6.2 我踩过的一些坑与建议

最后分享几个实操中总结的经验,这些大多是文档里不会写的。

第一个是关于容器启动顺序的坑。我在项目早期只用了depends_on,结果后端容器起来时MySQL还没有初始化完成,后端连库失败后直接退出。虽然restart: always会让容器自动重启,但每次都要等一会儿,而且如果后端启动时间比MySQL初始化时间还短,就会反复重启。后来我给MySQL加了健康检查,让后端等MySQL健康后再启动,这种问题就完全消失了。healthcheck大致配置是这样的:

mysql: healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-proot123456"] interval: 10s timeout: 5s retries: 5

然后后端的depends_on改成:

depends_on: mysql: condition: service_healthy

第二个建议是用IDEA的Docker插件来辅助排障。IntelliJ IDEA自带的Docker面板可以直接查看容器日志、进入容器终端、查看环境变量,甚至能直接查看镜像的分层信息。项目出问题时,我基本都是先在IDEA的容器面板里看日志,比在命令行里一次次docker logs要方便得多。还有一个有用的功能是docker inspect,可以查看容器的环境变量、挂载信息、网络配置,很多“明明改了配置不生效”的问题,一查环境变量就知道是哪一步配错了。

第三个建议是不要把数据库密码、Redis密码硬编码在代码或者Dockerfile里。这个项目规模不大,我用了明文的environment变量,但稍微正式一点的环境,建议用Docker的env_file配合.env文件管理敏感信息,或者用K8s的Secret机制。密码这种东西一旦写进镜像历史,推送到镜像仓库就等于泄露了,这点要特别小心。

回看整个Docker化过程,我最大的体会是:部署方案没有标准答案,不同团队、不同规模的项目,选型都不一样。单机项目用Docker Compose绰绰有余,K8s在业务量上来之后再上不迟。但把Spring Boot和Vue用容器化跑通,把每个镜像的构建细节、每个配置项背后的原因搞明白,很多部署层面的知识就一通百通了。如果大家照着这篇配置仍然遇到奇怪的问题,多半不是Docker的问题,而是某个路径、时区、字符集的小细节没对上,这时候耐心一点,逐层排查,总能找到那个“隐藏的”变量。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/18 2:51:50

激光雷达点云数据处理全流程:Terrasolid从分类到成果交付

简介:一份面向遥感测绘、激光雷达点云处理学习者的专业参考文献,以PDF论文形式讲解基于Terrasolid软件的点云数据处理全流程。内容系统阐述机载LiDAR对地定位原理,重点分析点云滤波与分类方法,包括移动窗口法、数学形态滤波、基于…

作者头像 李华
网站建设 2026/9/18 2:51:29

Spring Boot购物推荐系统实战:协同过滤算法与电商业务整合全解析

做购物推荐网站这个题目,在Spring Boot毕设里属于常青树了——既有标准化的CRUD、权限、购物车、订单这套“保底”功能,又能通过推荐引擎把项目的技术含量拉起来,不管是课程设计还是毕业论文答辩,讲出来都比纯增删改查有看点。我之…

作者头像 李华
网站建设 2026/9/18 2:49:30

oh-my-zsh rand-quote 插件:一条命令随机获取英文名人名言

oh-my-zsh rand-quote 插件:一条命令随机获取英文名人名言 【免费下载链接】ohmyzsh 🙃 A delightful community-driven (with 2,500 contributors) framework for managing your zsh configuration. Includes 300 optional plugins (rails, git, macOS,…

作者头像 李华
网站建设 2026/9/18 2:47:51

Vue Router深度实践:从路由表设计到动态权限与性能优化

接手一个中后台项目时,我做的第一件事往往是打开路由文件。见过最离谱的router/index.js有一千多行,导航守卫里堆着登录判断、页面标题、埋点、权限校验,业务路由和布局路由混在一起,同一个组件在三个不同路由下重复注册&#xff…

作者头像 李华
网站建设 2026/9/18 2:47:05

企业级Flutter模块化架构:多包分层+状态管理+路由实战

1. 项目概述与架构设计的核心思路1.1 企业级 Flutter 项目到底缺什么聊这个话题之前,先说个我自己的经历。早年间做过一个 Flutter 项目,功能不复杂,就十几个页面,当时图省事,所有代码全塞在lib下面,按page…

作者头像 李华
网站建设 2026/9/18 2:46:58

Steam成就系统接入指南:RequestCurrentStats报错排查与Unity实践

上周帮一个朋友排查Unity项目接入Steam成就系统的报错,卡在SteamUserStats.RequestCurrentStats()这个调用上,整整折腾了一个下午。说起来这个API本身并不复杂,就是请求当前用户的所有统计数据,但就是这样一个基础方法&#xff0c…

作者头像 李华