You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PowerShell HttpListener接收multipart/form-data上传文件如何保存到本地

PowerShell HttpListener 处理multipart/form-data文件上传解决方案

错误根因

  • 你当前使用的StreamReader.ReadToEnd()方法会把二进制格式的请求流转换为字符串,图片这类二进制文件转字符串会发生不可逆的编码损坏,同时字符串类型也无法直接传入要求字节数组参数的WriteAllBytes方法
  • 当前请求的ContentType为multipart/form-data类型,请求体中不止包含文件二进制内容,还包含表单边界、Content-Disposition元数据等信息,直接写入文件肯定无法得到可用的文件
  • 你原有的Invoke-GetBody函数仅适用于读取文本格式的请求体,不适合处理二进制文件上传场景

正确实现代码

你需要直接读取原始字节流,解析multipart表单结构提取文件内容,完整实现逻辑如下:

# 辅助函数:在字节数组中查找指定字节序列的偏移位置
function Find-Bytes {
    param(
        [byte[]]$Bytes,
        [byte[]]$Pattern,
        [int]$StartOffset = 0
    )
    for ($i = $StartOffset; $i -le $Bytes.Length - $Pattern.Length; $i++) {
        $match = $true
        for ($j = 0; $j -lt $Pattern.Length; $j++) {
            if ($Bytes[$i + $j] -ne $Pattern[$j]) {
                $match = $false
                break
            }
        }
        if ($match) { return $i }
    }
    return -1
}

# 1. 从请求头提取表单边界
$boundary = $script:Request.ContentType.Split('=')[1].Trim()
$boundaryBytes = [System.Text.Encoding]::ASCII.GetBytes("--$boundary")

# 2. 读取完整的原始请求字节流,避免编码损坏
$memoryStream = New-Object System.IO.MemoryStream
$script:Request.InputStream.CopyTo($memoryStream)
$allBytes = $memoryStream.ToArray()
$memoryStream.Dispose()
$script:Request.InputStream.Dispose()

# 3. 定位文件内容的起止位置
$firstBoundaryIndex = Find-Bytes -Bytes $allBytes -Pattern $boundaryBytes
if ($firstBoundaryIndex -eq -1) { throw "无效的multipart表单:未找到边界" }

$headerEndPattern = [System.Text.Encoding]::ASCII.GetBytes("`r`n`r`n")
$headerEndIndex = Find-Bytes -Bytes $allBytes -Pattern $headerEndPattern -StartOffset ($firstBoundaryIndex + $boundaryBytes.Length)
if ($headerEndIndex -eq -1) { throw "无效的multipart表单:未找到表头结束标识" }

$nextBoundaryIndex = Find-Bytes -Bytes $allBytes -Pattern $boundaryBytes -StartOffset ($headerEndIndex + $headerEndPattern.Length)
if ($nextBoundaryIndex -eq -1) { throw "无效的multipart表单:未找到结束边界" }

# 4. 提取文件字节数组
$fileContentLength = $nextBoundaryIndex - $headerEndIndex - $headerEndPattern.Length - 2 # 减去文件结尾的\r\n
$fileBytes = New-Object byte[] $fileContentLength
[Array]::Copy($allBytes, $headerEndIndex + $headerEndPattern.Length, $fileBytes, 0, $fileContentLength)

# 5. 保存到本地文件
[System.IO.File]::WriteAllBytes('C:\test.png', $fileBytes)

扩展说明

  • 如果你的表单包含多个字段或者多个文件,可以循环查找边界,逐个解析每个区块的Content-Disposition头,匹配filename="xxx"规则判断是否为文件字段,同时提取原始文件名
  • 如果需要支持中文文件名,需要额外处理Content-Disposition的编码适配逻辑

内容的提问来源于stack exchange,提问作者CrommCruach

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 15:45:02