179 lines
8.4 KiB
PowerShell
179 lines
8.4 KiB
PowerShell
# ============================================================================
|
||
# MilliSim 后端部署脚本(IIS 独立后端 + 反向代理架构)
|
||
# 在部署服务器上以管理员身份运行 PowerShell 执行此脚本
|
||
# 用法:.\deploy-to-iis.ps1 -DeployDir "C:\MilliSim\Backend" -ZipPath "C:\Deploy\MilliSim.Api.publish.clean.zip"
|
||
# ============================================================================
|
||
|
||
param(
|
||
[Parameter(Mandatory=$true)]
|
||
[string]$DeployDir,
|
||
[Parameter(Mandatory=$true)]
|
||
[string]$ZipPath,
|
||
[string]$ServiceName = "MilliSimApi"
|
||
)
|
||
|
||
$ErrorActionPreference = "Stop"
|
||
|
||
Write-Host "================================================" -ForegroundColor Cyan
|
||
Write-Host " MilliSim 后端部署脚本" -ForegroundColor Cyan
|
||
Write-Host "================================================" -ForegroundColor Cyan
|
||
Write-Host "部署目录: $DeployDir"
|
||
Write-Host "发布包: $ZipPath"
|
||
Write-Host "服务名: $ServiceName"
|
||
Write-Host ""
|
||
|
||
# 1. 前置检查
|
||
Write-Host "[1/7] 前置检查..." -ForegroundColor Yellow
|
||
if (-not (Test-Path $ZipPath)) { throw "发布包不存在: $ZipPath" }
|
||
if (-not (Test-Path $DeployDir)) { throw "部署目录不存在: $DeployDir" }
|
||
if (-not (Test-Path "$DeployDir\MilliSim.Api.dll")) { throw "部署目录下未找到 MilliSim.Api.dll,确认是否正确的部署目录" }
|
||
Write-Host " [OK] 检查通过" -ForegroundColor Green
|
||
|
||
# 2. 备份当前部署目录
|
||
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
|
||
$backupDir = "$DeployDir.bak_$timestamp"
|
||
Write-Host "[2/7] 备份当前部署目录到: $backupDir" -ForegroundColor Yellow
|
||
Copy-Item -Path $DeployDir -Destination $backupDir -Recurse -Force
|
||
Write-Host " [OK] 备份完成" -ForegroundColor Green
|
||
|
||
# 3. 停止后端服务
|
||
Write-Host "[3/7] 停止后端服务..." -ForegroundColor Yellow
|
||
$serviceStopped = $false
|
||
try {
|
||
$svc = Get-Service -Name $ServiceName -ErrorAction Stop
|
||
if ($svc.Status -eq "Running") {
|
||
Stop-Service -Name $ServiceName -Force
|
||
Start-Sleep -Seconds 2
|
||
Write-Host " [OK] Windows 服务 '$ServiceName' 已停止" -ForegroundColor Green
|
||
} else {
|
||
Write-Host " [SKIP] 服务已处于停止状态" -ForegroundColor Gray
|
||
}
|
||
$serviceStopped = $true
|
||
} catch {
|
||
Write-Host " [INFO] 未找到 Windows 服务 '$ServiceName',尝试查找 dotnet 进程..." -ForegroundColor Gray
|
||
$procs = Get-Process -Name "dotnet","MilliSim.Api" -ErrorAction SilentlyContinue | Where-Object { $_.Path -like "*$DeployDir*" }
|
||
if ($procs) {
|
||
$procs | Stop-Process -Force
|
||
Start-Sleep -Seconds 2
|
||
Write-Host " [OK] 已终止 dotnet 进程: $($procs.Id -join ', ')" -ForegroundColor Green
|
||
} else {
|
||
Write-Host " [INFO] 未找到运行中的后端进程" -ForegroundColor Gray
|
||
}
|
||
}
|
||
|
||
# 4. 备份当前 appsettings.json(保留服务器配置)
|
||
$appSettingsPath = "$DeployDir\appsettings.json"
|
||
$appSettingsBackup = "$DeployDir\appsettings.json.server_backup"
|
||
if (Test-Path $appSettingsPath) {
|
||
Copy-Item -Path $appSettingsPath -Destination $appSettingsBackup -Force
|
||
Write-Host "[4/7] 已备份服务器 appsettings.json 到: $appSettingsBackup" -ForegroundColor Green
|
||
} else {
|
||
Write-Host "[4/7] 部署目录无 appsettings.json,跳过备份" -ForegroundColor Gray
|
||
}
|
||
|
||
# 5. 解压新代码(不删除 wwwroot/uploads 和 wwwroot/backups 的文件)
|
||
Write-Host "[5/7] 解压新代码到部署目录..." -ForegroundColor Yellow
|
||
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
||
$zip = [System.IO.Compression.ZipFile]::OpenRead($ZipPath)
|
||
try {
|
||
foreach ($entry in $zip.Entries) {
|
||
# 跳过 wwwroot/uploads 和 wwwroot/backups 下的所有文件(保留服务器上的上传文件)
|
||
if ($entry.FullName -match "^wwwroot/uploads/" -and $entry.Length -gt 0) { continue }
|
||
if ($entry.FullName -match "^wwwroot/backups/" -and $entry.Length -gt 0) { continue }
|
||
|
||
$targetPath = Join-Path $DeployDir $entry.FullName
|
||
$targetDir = Split-Path $targetPath -Parent
|
||
if (-not (Test-Path $targetDir)) { New-Item -ItemType Directory -Path $targetDir -Force | Out-Null }
|
||
|
||
if ($entry.Length -gt 0) {
|
||
[System.IO.Compression.ZipFileExtensions]::ExtractToFile($entry, $targetPath, $true)
|
||
} elseif (-not (Test-Path $targetPath)) {
|
||
New-Item -ItemType Directory -Path $targetPath -Force | Out-Null
|
||
}
|
||
}
|
||
Write-Host " [OK] 解压完成(已保留 wwwroot/uploads 和 wwwroot/backups 中的文件)" -ForegroundColor Green
|
||
} finally {
|
||
$zip.Dispose()
|
||
}
|
||
|
||
# 6. 恢复服务器 appsettings.json(如果存在备份)
|
||
if (Test-Path $appSettingsBackup) {
|
||
Copy-Item -Path $appSettingsBackup -Destination $appSettingsPath -Force
|
||
Write-Host "[6/7] 已恢复服务器 appsettings.json(保留端口/连接字符串配置)" -ForegroundColor Green
|
||
} else {
|
||
Write-Host "[6/7] 未恢复 appsettings.json(使用发布包默认配置)" -ForegroundColor Gray
|
||
}
|
||
|
||
# 7. 启动后端服务
|
||
Write-Host "[7/7] 启动后端服务..." -ForegroundColor Yellow
|
||
if ($serviceStopped) {
|
||
try {
|
||
Start-Service -Name $ServiceName -ErrorAction Stop
|
||
Start-Sleep -Seconds 3
|
||
$svc = Get-Service -Name $ServiceName
|
||
if ($svc.Status -eq "Running") {
|
||
Write-Host " [OK] Windows 服务 '$ServiceName' 已启动" -ForegroundColor Green
|
||
} else {
|
||
Write-Host " [WARN] 服务启动状态: $($svc.Status)" -ForegroundColor Yellow
|
||
}
|
||
} catch {
|
||
Write-Host " [ERROR] 服务启动失败: $_" -ForegroundColor Red
|
||
Write-Host " 请手动启动服务或检查日志" -ForegroundColor Yellow
|
||
}
|
||
} else {
|
||
Write-Host " [INFO] 之前未通过 Windows 服务停止,请用原启动方式重启后端" -ForegroundColor Gray
|
||
Write-Host " 例如: cd $DeployDir; dotnet MilliSim.Api.dll --urls http://localhost:30001" -ForegroundColor Gray
|
||
}
|
||
|
||
# 验证
|
||
Write-Host ""
|
||
Write-Host "================================================" -ForegroundColor Cyan
|
||
Write-Host " 部署完成,开始验证" -ForegroundColor Cyan
|
||
Write-Host "================================================" -ForegroundColor Cyan
|
||
Start-Sleep -Seconds 5
|
||
|
||
Write-Host "[验证 1] 检查后端端口 30001 是否监听..." -ForegroundColor Yellow
|
||
$conn = Test-NetConnection -ComputerName localhost -Port 30001 -WarningAction SilentlyContinue
|
||
if ($conn.TcpTestSucceeded) {
|
||
Write-Host " [OK] 端口 30001 监听正常" -ForegroundColor Green
|
||
} else {
|
||
Write-Host " [FAIL] 端口 30001 未监听,请检查后端启动日志" -ForegroundColor Red
|
||
}
|
||
|
||
Write-Host "[验证 2] 调用 /api/system/public-settings ..." -ForegroundColor Yellow
|
||
try {
|
||
$resp = Invoke-WebRequest -Uri "http://localhost:30001/api/system/public-settings" -UseBasicParsing -TimeoutSec 10
|
||
Write-Host " [OK] HTTP $($resp.StatusCode)" -ForegroundColor Green
|
||
} catch {
|
||
Write-Host " [FAIL] 请求失败: $_" -ForegroundColor Red
|
||
}
|
||
|
||
Write-Host "[验证 3] 检查 /uploads/ 路径是否由后端服务 ..." -ForegroundColor Yellow
|
||
try {
|
||
$resp = Invoke-WebRequest -Uri "http://localhost:30001/uploads/" -UseBasicParsing -TimeoutSec 10
|
||
Write-Host " [OK] HTTP $($resp.StatusCode)" -ForegroundColor Green
|
||
} catch {
|
||
$code = $_.Exception.Response.StatusCode.value__
|
||
if ($code -eq 404) {
|
||
Write-Host " [OK] HTTP 404(目录浏览禁用,符合预期)" -ForegroundColor Green
|
||
} else {
|
||
Write-Host " [INFO] HTTP $code" -ForegroundColor Gray
|
||
}
|
||
}
|
||
|
||
Write-Host ""
|
||
Write-Host "================================================" -ForegroundColor Cyan
|
||
Write-Host " 部署脚本结束" -ForegroundColor Cyan
|
||
Write-Host "================================================" -ForegroundColor Cyan
|
||
Write-Host ""
|
||
Write-Host "下一步:在浏览器访问前端页面,验证以下 4 个问题是否全部解决:" -ForegroundColor White
|
||
Write-Host " 1. 员工管理页面头像加载(应返回 /uploads/avatars/xxx.png,不再请求 COS)"
|
||
Write-Host " 2. 轮播图列表页图片加载"
|
||
Write-Host " 3. 项目封面/视频加载"
|
||
Write-Host " 4. WebGL 资源加载(.unityweb 文件应返回 200 + application/octet-stream)"
|
||
Write-Host ""
|
||
Write-Host "如需回滚:删除 $DeployDir,重命名 $backupDir 为 $DeployDir,重启服务" -ForegroundColor Gray
|
||
Write-Host ""
|
||
Write-Host "如服务器上缺少 COS 模式时上传的旧文件,可调用迁移端点补齐:"
|
||
Write-Host " Invoke-WebRequest -Uri 'http://localhost:30001/api/system/migrate-cos-to-local' -Method POST -Headers @{Authorization='Bearer <admin token>'}"
|