通过 REST API 上传工作流程中的一些 .exe 输出文件:已损坏,文件大小增加

问题描述 投票:0回答:1

我的 Github 操作“发布”:

name: publish

on:
  push:
    tags:
      - release-*

jobs:
  test:
   uses: ./.github/workflows/test.yml
   secrets: inherit
  publish:
    name: Publish
    needs: test
    
    runs-on: windows-latest
    strategy:
      matrix:
        dotnet-version: [ '8.0.x' ]

    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
          token: ${{ secrets.CHECKOUT_TOKEN }}
      - name: Instalar .NET SDK ${{ matrix.dotnet-version }}
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: ${{ matrix.dotnet-version }}
      - name: Agregar DevExpress Nuget source
        run: dotnet nuget add source "https://nuget.devexpress.com/..../api"
      - name: Ejecutar build.ps1
        shell: pwsh
        env:
          DISABLE_PROGRESS: 1
          NEXION_USERNAME: ${{ secrets.NEXION_USERNAME }}
          NEXION_PASSWORD: ${{ secrets.NEXION_PASSWORD }}
        run: .\build.ps1 -enableOutput
      - uses: actions/upload-artifact@v4
        with:
          name: release-artifacts
          path: .\build\**

步骤

.\build.ps1 -enableOutput
是一个脚本,它执行所有.exe生成,然后通过API将其输出上传到我自己的网站,如下所示:


function Get-MultipartBody($boundary, $paths, $fields) {
    $boundary = "`r`n--" + $boundary
    $multipart = @($fields.Keys + $paths) | % {
            $name = if ($paths.IndexOf($_) -ne -1) {'upload_files'} else {$_}
            $contentDisposition = "Content-Disposition: form-data; name=`"$name`""
            $contentType = ''
            $data = ''
            if ($name -eq 'upload_files') {
                $filename = [IO.Path]::GetFileName($_)
                $contentDisposition = $contentDisposition + "; filename=`"$filename`""
                $contentType = "`r`n`Content-Type: application/octet-stream"
                $bytes = [IO.File]::ReadAllBytes($_)
                $data = [Text.Encoding]::GetEncoding('ISO-8859-1').GetString($bytes)
            } else {
                $data = $fields.Item($_)
            }
            return $contentDisposition + $contentType + "`r`n`r`n" + $data
        }
    $middle = $multipart -join ($boundary + "`r`n")
    return $boundary + "`r`n" + $middle + $boundary + "--"
}
...
$body = Get-MultipartBody $boundary $files $fields
...

Invoke-WebRequest -Uri "http://my-domain.com.ar/services/release/publish/add" -Method Post -Body $body -WebSession $session -ContentType "multipart/form-data; boundary=$boundary" -TimeoutSec 300000 -MaximumRedirection 0
...

我的问题是,不知何故,文件到达我的服务器 API,并被存储,但它们已损坏,而步骤

actions/upload-artifact@v4
在操作本身上很好地存储文件。

举个例子:

神器NexionSmartERP-AnyCPU-24.1.0.1.exe为82M(使用actions/upload-artifact@v4) 上传到我的服务器 API NexionSmartERP-AnyCPU-24.1.0.1.exe 的相同文件为 122M(几乎大了 50%,已损坏)

顺便说一句,.uild.ps1 脚本在我的主机上本地运行时可以正常发布到我的服务器 API。

我做错了什么?

我发现了一些东西https://stackoverflow.com/a/41995428

powershell rest http github-actions
1个回答
0
投票

解决方案是避免从二进制数据构建字符串,正如 @jdweng 指出的那样。

重构了我的 PowerShell 函数来构建临时文件,该文件支持文件上传和普通字段。


function Get-MultipartBody($boundary, $files, $fields) {
    $tempFile = [System.IO.Path]::GetTempFileName()
    $UTF8woBOM = New-Object "System.Text.UTF8Encoding" -ArgumentList @($false)
    # Campos
    if ($fields.Keys.Count -gt 0) {
        $sw = New-Object System.IO.StreamWriter($tempFile, $true, $UTF8woBOM)
        foreach($field in $fields.Keys) {
            $sw.Write("`r`n--$boundary`r`nContent-Disposition: form-data; name=`"$field`"`r`n`r`n$($fields.Item($field))")
        }
        $sw.Close()
    }
    # Archivos binarios
    if ($files.Length -gt 0) {
        $files | % {
            $sw = New-Object System.IO.StreamWriter($tempFile, $true, $UTF8woBOM)
            $fileName = [System.IO.Path]::GetFileName($_)
            $sw.Write("`r`n--$boundary`r`nContent-Disposition: form-data;name=`"upload_files`";filename=`"$fileName`"")
            $sw.Write("`r`nContent-Type: application/octet-stream`r`n`r`n")
            $sw.Close()

            $fs = New-Object System.IO.FileStream($tempFile, [System.IO.FileMode]::Append)
            $bw = New-Object System.IO.BinaryWriter($fs)
            $fileBinary = [System.IO.File]::ReadAllBytes($_)
            $bw.Write($fileBinary)
            $bw.Close()
        }
    }
    $sw = New-Object System.IO.StreamWriter($tempFile, $true, $UTF8woBOM)
    $sw.Write("`r`n--$boundary--`r`n")
    $sw.Close()
    $tempFile
}
© www.soinside.com 2019 - 2024. All rights reserved.