- RemoteRoot 固定为 /wwwroot (IIS 站点物理根), 网页必须存放于 wwwroot 才可访问 - ftp_upload.ps1: 每文件独立连接、上传后校验大小、3次重试、日志记录 - 新增 ftp_fast.ps1 (快速覆盖上传) 与 ftp_sync.ps1 (仅补传缺失/大小不符文件) - 上传前删除服务商默认欢迎页 default.html, 避免优先于 index.html
131 lines
5.3 KiB
PowerShell
131 lines
5.3 KiB
PowerShell
# ============================================================
|
|
# 文传易 一键发布脚本
|
|
# 1. dotnet publish 后端 (Release, net8.0)
|
|
# 2. npm run build 前端 (Vite, dist)
|
|
# 3. FTP 上传合并产物至 IIS 站点根目录
|
|
#
|
|
# 重要: 官方提示 —— 网页必需存放在 wwwroot 目录下才能被访问!
|
|
# 因此 RemoteRoot 固定为 /wwwroot (FTP 上的目录, 即 IIS 站点物理根)
|
|
#
|
|
# 用法:
|
|
# powershell -ExecutionPolicy Bypass -File deploy/publish.ps1
|
|
#
|
|
# 前置: 本机已安装 .NET 8 SDK / Node.js >=18; FTP 凭据见下方变量
|
|
# ============================================================
|
|
param(
|
|
[string]$FtpHost = "116.198.221.125",
|
|
[int] $FtpPort = 21,
|
|
[string]$FtpUser = "wenchuanyi",
|
|
[string]$FtpPass = "r7P^f*v7rFts",
|
|
[string]$RemoteRoot = "/wwwroot", # FTP 远端目标目录 = IIS 站点根目录 (勿改!)
|
|
[switch]$SkipBuild # 跳过构建, 仅上传已有产物
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
$Root = Split-Path -Parent $PSScriptRoot
|
|
$BackendDir = Join-Path $Root "backend\WenChuanyi.Api"
|
|
$FrontendDir = Join-Path $Root "frontend"
|
|
$PublishDir = Join-Path $BackendDir "bin\Release\net8.0\publish"
|
|
$DistDir = Join-Path $FrontendDir "dist"
|
|
$StagingDir = Join-Path $env:TEMP "wcy_publish_staging"
|
|
|
|
# ---------------- 1. 构建 ----------------
|
|
if (-not $SkipBuild) {
|
|
Write-Host "==> [1/3] 构建后端..." -ForegroundColor Cyan
|
|
Push-Location $BackendDir
|
|
try { dotnet publish -c Release --nologo -v q }
|
|
finally { Pop-Location }
|
|
|
|
Write-Host "==> [2/3] 构建前端..." -ForegroundColor Cyan
|
|
if (-not (Test-Path (Join-Path $FrontendDir "node_modules"))) {
|
|
Write-Host " 首次构建, 安装 npm 依赖..." -ForegroundColor Yellow
|
|
Push-Location $FrontendDir
|
|
try { npm install --no-audit --no-fund }
|
|
finally { Pop-Location }
|
|
}
|
|
Push-Location $FrontendDir
|
|
try { npm run build }
|
|
finally { Pop-Location }
|
|
} else {
|
|
Write-Host "==> [1-2/3] 跳过构建 (SkipBuild)..." -ForegroundColor Yellow
|
|
}
|
|
|
|
if (-not (Test-Path $PublishDir)) { throw "后端发布目录不存在: $PublishDir (请先 dotnet publish)" }
|
|
if (-not (Test-Path $DistDir)) { throw "前端产物目录不存在: $DistDir (请先 npm run build)" }
|
|
|
|
# ---------------- 2. 合并产物到临时目录 ----------------
|
|
Write-Host "==> [3/3] 合并产物并 FTP 上传..." -ForegroundColor Cyan
|
|
if (Test-Path $StagingDir) { Remove-Item $StagingDir -Recurse -Force }
|
|
New-Item -ItemType Directory -Path $StagingDir -Force | Out-Null
|
|
|
|
Copy-Item "$DistDir\*" $StagingDir -Recurse -Force
|
|
Copy-Item "$PublishDir\*" $StagingDir -Recurse -Force
|
|
|
|
Write-Host " 产物合计: $((Get-ChildItem $StagingDir -File -Recurse | Measure-Object).Count) 个文件" -ForegroundColor Gray
|
|
|
|
# ---------------- FTP 工具函数 ----------------
|
|
function New-FtpRequest([string]$path, [string]$method) {
|
|
$uri = "ftp://${FtpHost}:${FtpPort}/" + $path.TrimStart('/')
|
|
$req = [System.Net.FtpWebRequest]::Create($uri)
|
|
$req.Method = $method
|
|
$req.Credentials = New-Object System.Net.NetworkCredential($FtpUser, $FtpPass)
|
|
$req.UsePassive = $true
|
|
$req.UseBinary = $true
|
|
$req.KeepAlive = $false
|
|
return $req
|
|
}
|
|
|
|
function New-FtpDirectory([string]$remotePath) {
|
|
$req = New-FtpRequest $remotePath ([System.Net.WebRequestMethods+Ftp]::MakeDirectory)
|
|
try { $null = $req.GetResponse() }
|
|
catch { } # 目录已存在时报错, 忽略
|
|
}
|
|
|
|
function Send-FtpFile([string]$localPath, [string]$remotePath) {
|
|
$req = New-FtpRequest $remotePath ([System.Net.WebRequestMethods+Ftp]::UploadFile)
|
|
$bytes = [System.IO.File]::ReadAllBytes($localPath)
|
|
$req.ContentLength = $bytes.Length
|
|
$stream = $req.GetRequestStream()
|
|
try {
|
|
$stream.Write($bytes, 0, $bytes.Length)
|
|
} finally {
|
|
$stream.Close()
|
|
}
|
|
$resp = $req.GetResponse()
|
|
try { $resp.Close() } catch { }
|
|
}
|
|
|
|
function Send-FtpDirectory([string]$localDir, [string]$remoteDir) {
|
|
foreach ($dir in Get-ChildItem $localDir -Directory) {
|
|
$child = "$remoteDir/$($dir.Name)"
|
|
New-FtpDirectory $child
|
|
Send-FtpDirectory $dir.FullName $child
|
|
}
|
|
foreach ($file in Get-ChildItem $localDir -File) {
|
|
$remoteFile = "$remoteDir/$($file.Name)"
|
|
Send-FtpFile $file.FullName $remoteFile
|
|
Write-Host " UP $remoteFile" -ForegroundColor Gray
|
|
}
|
|
}
|
|
|
|
# ---------------- 上传 ----------------
|
|
# 删除服务商默认欢迎页 default.html, 避免 IIS 默认文档优先于 index.html
|
|
function Remove-FtpFile([string]$remotePath) {
|
|
$req = New-FtpRequest $remotePath ([System.Net.WebRequestMethods+Ftp]::DeleteFile)
|
|
try { $null = $req.GetResponse(); Write-Host " DEL $remotePath" -ForegroundColor DarkGray }
|
|
catch { }
|
|
}
|
|
Remove-FtpFile "$RemoteRoot/default.html"
|
|
|
|
New-FtpDirectory $RemoteRoot
|
|
Send-FtpDirectory $StagingDir $RemoteRoot
|
|
|
|
Remove-Item $StagingDir -Recurse -Force
|
|
|
|
Write-Host ""
|
|
Write-Host "============================================================" -ForegroundColor Green
|
|
Write-Host " 发布完成! 请手动回收 IIS 应用程序池使新版本生效:" -ForegroundColor Green
|
|
Write-Host " IIS 管理器 -> 应用程序池 -> wenchuanyi -> 右键回收" -ForegroundColor Green
|
|
Write-Host " 或: appcmd recycle apppool /apppool.name:wenchuanyi" -ForegroundColor Green
|
|
Write-Host "============================================================" -ForegroundColor Green
|