Использование PS 5.1.14409.1005 на W2K12 R2 x64.
Насколько я вижу, есть два способа сделать это -
- Создать тело составной части / формы вручную, следуя формат RF C
- Использовать MultipartFormDataContent. NET Типы
Я пробовал MultipartFormDataContent, но он не работает, когда я добавляю построенный объект в тело Invoke-WebRequest
параметр (см. ниже, например), и мне удалось создать вручную с частями текстовой формы, но у меня возникли проблемы с двоичным. На снимке экрана показан захват запроса fiddler от Invoke-WebRequest
powershell, который не работает, и от chrome, который работает. Двоичное содержимое отличается, и я не уверен, как получить его так же, как chrome.
Вот первые несколько байтов в шестнадцатеричном виде, сравнивающие фактический файл с тем, что chrome и powershell отправлены в fiddler , Во всем остальном есть небольшие отличия ...
file: 30 82 1D 32 02 01 03 30 82 1C F8
chrome: 30 82 1D 32 02 01 03 30 82 1C F8
ps: 30 2C 1D 32 02 01 03 30 2C 1C F8
Вот мой текущий код. Двоичный раздел заполняется Get-Content -Path $FilePath -Raw
.
function Publish-RestApiFile {
param ([string] $Url, [hashtable] $Params, [string] $FilePath, [string] $FileParamName)
Add-Type -AssemblyName System.Web
$bnd = [System.Guid]::NewGuid().ToString().ToLower().Replace('-','').PadLeft(40,'-')
$content_type = "multipart/form-data; boundary=$bnd"
$LF = "`r`n"
$lines = @("--${bnd}${LF}")
$Params.GetEnumerator() | ForEach-Object {
$lines += "$('Content-Disposition: form-data; name="{0}"' -f $_.Name)${LF}${LF}$($_.Value)${LF}"
$lines += "--${bnd}${LF}"
}
$file_name = Split-Path -Path $FilePath -Leaf
$mime_type = [System.Web.MimeMapping]::GetMimeMapping($FilePath)
$ct = Get-Content -Path $FilePath -Raw
$lines += ('Content-Disposition: form-data; name="{0}"; filename="{1}"' -f $FileParamName,$file_name)+${LF}
$lines += ("Content-Type: ${mime_type}${LF}${LF}"),$ct,${LF}
$lines += ("--${bnd}--"+${LF})
$lines = $lines -join ''
Invoke-RestMethod -Uri $url -Method Post -Body $lines -ContentType $content_type -MaximumRedirection 0
}
Это показывает строку тела, сгенерированную текущим кодом -
Это показывает различия в двоичном виде из запроса захватывает в Fiddler между PS Invoke-WebRequest
(LEFT) и chrome (RIGHT).
Вот пример использования MultipartFormDataContent. Fiddler показывает, что объект просто приводится в строку в теле, например, System.Net.Http.StringContent System.Net.Http.StringContent System.Net.Http.StreamContent
.
function Publish-RestApiFile2 {
param ([string] $Url, [hashtable] $Params, [string] $FilePath, [string] $FileParamName)
Add-Type -AssemblyName System.Net.Http, System.Web
$mime_type = [System.Web.MimeMapping]::GetMimeMapping($FilePath)
$form = [System.Net.Http.MultipartFormDataContent]::New()
foreach ($param in $Params.GetEnumerator()) {
$header = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("form-data")
$header.Name = $param.Name
$content = [System.Net.Http.StringContent]::new($param.Value)
$content.Headers.ContentDisposition = $header
$form.Add($content)
}
$stream = [System.IO.FileStream]::New($FilePath, 'Open')
$header = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("form-data")
$header.Name = $FileParamName
$header.FileName = (Split-Path -Path $FilePath -Leaf)
$content = [System.Net.Http.StreamContent]::New($stream)
$content.Headers.ContentDisposition = $header
$content.Headers.ContentType = [System.Net.Http.Headers.MediaTypeHeaderValue]::Parse($mime_type)
$form.Add($content)
Invoke-WebRequest -Uri $Url -Method Post -Body $form -ContentType 'multipart/form-data'
#Invoke-WebRequest -Uri $Url -Method Post -Body $form
$stream.Close(); $stream.Dispose()
}