【问题标题】:Trouble with Powershell script to call HTTP POST with multipart/form-data使用 multipart/form-data 调用 HTTP POST 的 Powershell 脚本出现问题
【发布时间】:2014-08-24 06:32:14
【问题描述】:

我正在开发一个 powershell 脚本,它应该使用 HTTP POST 方法调用 REST API。 REST API 用于从外部备份文件恢复应用程序特定的备份资源。表单数据中备份文件的 KeyName 必须为“backupFile”。 内容类型是多部分/表单数据。这是我正在做的事情:

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的数据表单,返回:Bad Request (400)

我在这里做错了什么?

【问题讨论】:

  • 我没有答案,但除非此代码必须在 PowerShell 2.0 上运行,否则您应该考虑使用 Invoke-RestMethod:technet.microsoft.com/en-us/library/hh849971.aspx
  • 这种事情很难解决。我的一般建议是从telerik.com/fiddler 获取 Fiddler(它是免费的)并用它来观察您的脚本和有效的东西(卷曲、交互式表单提交等)之间的差异。了解成功请求和失败请求之间的区别通常足以让您度过难关。
  • briantist,不幸的是,这必须在 powershell 2.0 中。
  • keith hill,我现在把范围缩小了。问题在于对 sql.gz 文件进行编码,或者在于我提供内容类型或内容编码标头的方式。 “请求正文”的内容类型应该是 application/x-gzip 或 application/octet-stream,而“请求标头”的内容类型应该是“multipart/form-data”。您认为我指定内容类型的方式或编码方式有什么问题吗?当我将其与提琴手的请求正文进行比较时,内容类型看起来不错。但不知道如何弄清楚编码部分!

标签: rest powershell multipartform-data


【解决方案1】:

在这种情况下,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 来做到这一点,这一点也不好玩,尤其是当你开始涉及二进制数据时。在经历了很多挫折和头疼之后,我最终得到了以下内容来转换值的哈希表并输出多部分。抱歉,我无法准确发现您的代码有什么问题,但也许这可以完全为您工作,或者引导您确定问题所在。

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
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-02
    • 2014-05-13
    • 2023-02-02
    • 2019-12-03
    • 2011-07-28
    • 1970-01-01
    • 2016-09-08
    相关资源
    最近更新 更多