使用Powershell脚本来解决使用multipart / form-data调用HTTP POST的问题

时间:2014-08-24 06:32:14

标签: rest powershell multipartform-data

我正在开发一个powershell脚本,它应该使用HTTP POST方法调用REST API。 REST API用于从外部备份文件还原特定于应用程序的备份资源。表单数据中备份文件的KeyName必须是" backupFile"。 内容类型是multipart / form-data。这就是我在做的事情:

function invoke-rest {
param([string]$uri)
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
#$enc = [system.Text.Encoding]::UTF8
$request = [System.Net.HttpWebRequest]::Create($uri)
$request.Credentials = New-Object system.net.networkcredential("user","password")
$request.CookieContainer = New-Object System.Net.CookieContainer
$request.AllowWriteStreamBuffering = $true;
$boundary = "--------------"+(get-date -format yyyymmddhhmmss).ToString()
$header = "--"+$boundary
$body = $header + "`r`n" +"Content-Disposition: form-data; name='backupFile'; filename='somefile.sql.gz'"+"`r`n" + "Content-Type: multipart/form-data"+"`r`n`r`n"

$body = $body + [System.Text.Encoding]::UTF8.GetString($(Get-Content 'somefile.sql.gz' -Encoding byte)) + "`r`n"
$footer = $header+"--"
$body = $body + $footer

$bytes = [System.Text.Encoding]::UTF8.GetBytes($body)
$request.ContentType = "multipart/form-data; boundary="+$boundary
$request.Method = "Post"
$request.keepAlive = $true
$request.ContentLength = $bytes.Length

$requestStream = $request.GetRequestStream()
$requestStream.Write($bytes,0,$bytes.length);
$requestStream.Flush();
$requestStream.Close();

$response = $request.GetResponse()
$responseStream = $response.GetResponseStream()
$stream = new-object System.IO.StreamReader $responseStream
$xmlDump = $stream.ReadToEnd()
$output = [xml]$xmlDump
$response.close()
return $output
}
$uri = "http://localhost/rest/backups"
invoke-rest $uri

抛出错误: REST请求失败,必须存在名为backupFile的数据表单,返回:错误请求(400)

我在这里做错了什么?

1 个答案:

答案 0 :(得分:2)

在这种情况下,400可能意味着在生成

时出现了错误

文件是您需要在请求中提交的唯一参数吗?如果是这样,您可以使用WebClient.UploadFile API并让它处理生成大部分请求。

$client = New-Object System.Net.WebClient
$client.Credentials = $creds
$client.UploadFile('http://localhost/rest/backups', 'c:\temp\somefile.sql.gz')

如果您确实需要在mime多部分请求中提交多个参数,那么您就会看到一个痛苦的世界。我自己必须通过PowerShell做到这一点,而且根本不开心,特别是当你开始涉及二进制数据时。经过多次挫折之后headbanging,我最终得到以下内容来转换值的哈希表并输出一个多部分。抱歉,我无法确切地发现您的代码存在什么问题,但也许这可能会直接为您工作,或者引导您确定您的问题所在。

function ConvertTo-MimeMultiPartBody
{
    param(
        [Parameter(Mandatory=$true)]
        [string]$Boundary,
        [Parameter(Mandatory=$true)]
        [hashtable]$Data
    )

    $body = '';

    $Data.GetEnumerator() |% {
        $name = $_.Key
        $value = $_.Value

        $body += "--$Boundary`r`n"
        $body += "Content-Disposition: form-data; name=`"$name`""
        if ($value -is [byte[]]) {
            $fileName = $Data['FileName']
            if(!$fileName) {
                $fileName = $name
            }
            $body += "; filename=`"$fileName`"`r`n"
            $body += 'Content-Type: application/octet-stream'
            #ISO-8859-1 is only encoding where byte value == code point value
            $value = [System.Text.Encoding]::GetEncoding("ISO-8859-1").GetString($value)
        }
        $body += "`r`n`r`n"
        $body += $value
        $body += "`r`n"
    }
    $body += "--$boundary--"
    return $body
}