powershell调用休息方法多部分/表单数据

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

我目前正在尝试使用 REST API 将文件上传到网络服务器。正如前面提到的,我正在使用 PowerShell 来实现此目的。使用curl,这没有问题。调用看起来像这样:

curl -H "Auth_token:"$AUTH_TOKEN -H "Content-Type:multipart/form-data" -X POST -F appInfo='{"name": "test","description": "test"}' -F uploadFile=@/test/test.test https://server/api/

但是当涉及到使用 Invoke-Restmethod 命令将其导出到 powershell 时,我完全无能为力。据我搜索,不可能使用 Invoke-Rest 方法来实现此目的。 https://www.snip2code.com/Snippet/396726/PowerShell-V3-Multipart-formdata-example 但即使有了这个剪裁,我也不够聪明,无法完成这项工作,因为我不想上传两个文件,而是上传一个文件和一些参数。

如果有人能让我重回正轨,我将非常感激:o 谢谢!

rest powershell curl
8个回答
45
投票

@Bacon-Bits 的答案似乎对我不起作用。我的服务器以可能格式错误的表单数据正文拒绝了它:-(

我找到了这个要点,并根据我的目的对其进行了一些修剪。这是我的最终结果:

$FilePath = 'c:\temp\temp.txt';
$URL = 'http://your.url.here';

$fileBytes = [System.IO.File]::ReadAllBytes($FilePath);
$fileEnc = [System.Text.Encoding]::GetEncoding('UTF-8').GetString($fileBytes);
$boundary = [System.Guid]::NewGuid().ToString(); 
$LF = "`r`n";

$bodyLines = ( 
    "--$boundary",
    "Content-Disposition: form-data; name=`"file`"; filename=`"temp.txt`"",
    "Content-Type: application/octet-stream$LF",
    $fileEnc,
    "--$boundary--$LF" 
) -join $LF

Invoke-RestMethod -Uri $URL -Method Post -ContentType "multipart/form-data; boundary=`"$boundary`"" -Body $bodyLines

19
投票

它应该非常简单。摘自这个答案

$Uri = 'https://server/api/';
$Headers = @{'Auth_token'=$AUTH_TOKEN};
$FileContent = [IO.File]::ReadAllText('C:\test\test.test');
$Fields = @{'appInfo'='{"name": "test","description": "test"}';'uploadFile'=$FileContent};

Invoke-RestMethod -Uri $Uri -ContentType 'multipart/form-data' -Method Post -Headers $Headers -Body $Fields;

如果文件不是文本文件,您可能需要使用

[IO.File]::ReadAllBytes()

如果您上传大文件,这也可能无法正常工作。


18
投票

对于 PowerShell Core,这应该可以通过新的

-Form
参数开箱即用。

请参阅:https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-restmethod?view=powershell-7

$Uri = 'https://api.contoso.com/v2/profile'
$Form = @{
    firstName  = 'John'
    lastName   = 'Doe'
    email      = '[email protected]'
    avatar     = Get-Item -Path 'c:\Pictures\jdoe.png'
    birthday   = '1980-10-15'
    hobbies    = 'Hiking','Fishing','Jogging'
}
$Result = Invoke-RestMethod -Uri $Uri -Method Post -Form $Form

11
投票

我需要传递标头和更多参数(

insert=true
debug=true
)以及文件内容。这是我的版本,由 @jklemmack 扩展了脚本。

param([string]$path)

$Headers = @{Authorization = "Bearer ***************"}
$Uri = 'https://host:8443/api/upload'

$fileBytes = [System.IO.File]::ReadAllBytes($path);
$fileEnc = [System.Text.Encoding]::GetEncoding('ISO-8859-1').GetString($fileBytes);
$boundary = [System.Guid]::NewGuid().ToString(); 
$LF = "`r`n";

$bodyLines = ( 
    "--$boundary",
    "Content-Disposition: form-data; name=`"insert`"$LF",
    "true$LF",
    "--$boundary",
    "Content-Disposition: form-data; name=`"debug`"$LF",
    "true$LF",    
    "--$boundary",
    "Content-Disposition: form-data; name=`"file`"; filename=`"$path`"",
    "Content-Type: application/octet-stream$LF",
    $fileEnc,
    "--$boundary--$LF" 
) -join $LF

Invoke-RestMethod -Uri $Uri -Headers $Headers -Method Post -ContentType "multipart/form-data; boundary=`"$boundary`"" -Body $bodyLines

6
投票

所以,我最近一直在与这个问题作斗争,发现确实可以匹配curl功能,但如何正确地执行多部分/表单数据并不是立即显而易见的。上面的所有回复都涵盖了这个难题的重要部分,但我将尝试将它们全部联系在一起,以供下一个尝试在本机 Powershell 中实现curl 功能的抱歉的人使用。

@jklemmack 的解决方案让我走上了正轨,并且是最灵活的,因为它允许您专门构建表单数据内容,控制两个边界以及数据在其中的格式化方式.

对于尝试执行此操作的任何人,我认为使用适当的 Web 调试代理(例如 Fiddler (.net) 或 Burp Suite (java))武装自己非常重要,以便您可以详细检查每个 REST 调用以了解传递给 API 的数据的特定格式。

在我的具体情况下,我注意到curl在表单数据的每个部分上方插入了一个空行 - 因此为了扩展@jklemmack的示例,它将如下所示:

    $bodyLines = (
        "--$boundary",
        "Content-Disposition: form-data; name=`"formfield1`"",
        '',
        $formdata1,
        "--$boundary",
        "Content-Disposition: form-data; name=`"formfield2`"",
        '',
        $formdata2,
        "--$boundary",
        "Content-Disposition: form-data; name=`"formfield3`"; filename=`"$name_of_file_being_uploaded`"",
        "Content-Type: application/json",
        '',
        $content_of_file_being_uploaded,
        "--$boundary--"
    ) -join $LF

希望这可以在将来为某人节省很多时间!

我也仍然同意,如果您需要从头开始执行此操作,并且可以选择直接使用curl本机二进制文件(同时确保围绕安全性和合规性进行尽职调查),那么您可以利用它的成熟度和便利性提供。使用卷曲。最好由整个curl 社区对这种多部分逻辑进行严格测试和维护,而不是由内部开发或运营团队承担责任。


1
投票

执行此操作需要很多 hacky 代码,这里的大多数答案只是陈述它们。这些答案应该被删除或与互联网上的所有黑客博客一起存档。

最新版本(截至撰写本文时 PowerShell Core v7.2.6)。您所需要做的就是使用 Get-Item-Path 给出 Path。

    $Form = @{ 
        document=  Get-Item -Path .\image.png # no leading @ sign.
    }    

  $Result = Invoke-RestMethod -Uri $Uri -Method Post -Form $Form

请注意,在获取项目之前没有@符号,就像您放入curl中一样。我放了 @ 符号并破坏了我的请求。

参考:https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-restmethod?view=powershell-7#example-4--simplified-multipart-form-data -提交


1
投票

我在尝试使用

curl
 执行以下 
Invoke-RestMethod
命令时遇到了一些麻烦:

curl --request POST \
  --url https://example.com/upload_endpoint/ \
  --header 'content-type: multipart/form-data' \
  --form '[email protected]'
  -v

就我而言,事实证明,使用 powershell

curl
更容易。

$FilePath = "C:\example.csv"
$CurlExecutable = "C:\curl-7.54.1-win64-mingw\bin\curl.exe"

$CurlArguments = '--request', 'POST', 
                'https://example.com/upload_endpoint/',
                '--header', "'content-type: multipart/form-data'",
                '--form', "file=@$FilePath"
                '-v',

# Debug the above variables to see what's going to be executed
Write-Host "FilePath" $FilePath
Write-Host "CurlExecutable" $FilePath
Write-Host "CurlArguments" $CurlArguments

# Execute the curl command with its arguments
& $CurlExecutable @CurlArguments

curl 网站下载适合您操作系统的可执行文件。

以下是一些可以让您选择

curl
而不是powershell的
invoke-restmethod

的原因
  • 许多工具都可以生成curl命令
  • curl 支持上传大于 2GB 的文件(参见 Shukri Adams 评论

Curl 和 Powershell 的

invoke-restmethod
都是很好的解决方案。如果其他答案都不适合您,您可能需要考虑
curl
。通常最好坚持使用内置解决方案,但有时替代方案也很有用。


0
投票

尝试在 Windows 8.1 上使用 powershell v4 将文件上传到我的 upload.php 真是太痛苦了

# This code works and matches to a Firefox 78.6.0esr upload transmission verified via wireshark

$FilePath = 'c:\Temp\file-to-upload.txt';
$URL = 'http://127.0.0.1/upload.php';

$fileBytes = [System.IO.File]::ReadAllBytes($FilePath);
$fileEnc = [System.Text.Encoding]::GetEncoding('UTF-8').GetString($fileBytes);
$boundary = [System.Guid]::NewGuid().ToString(); 
$LF = "\r\n";

$bodyLines = "--$boundary $LF Content-Disposition: form-data; name='file'; filename='file-to-upload.txt' $LF Content-Type: application/octet-stream $LF $fileEnc $LF --$boundary-- $LF";

Invoke-RestMethod -Uri $URL -Method Post -ContentType "multipart/form-data; boundary=$boundary" -Body $bodyLines

供参考,upload.php 为:

<?php
    $uploaddir = '/var/www/uploads/';
    $uploadfile = $uploaddir . $_FILES['file']['name'];
    move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile)
?>

Wireshark 示例

POST /upload.php HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT; Windows NT 6.3; en-US) WindowsPowerShell/4.0
Content-Type: multipart/form-data; boundary=96985b62-451a-41fa-9eca-617e3599797c
Host: 127.0.0.1
Content-Length: 284
Connection: Keep-Alive

--96985b62-451a-41fa-9eca-617e3599797c \r\n Content-Disposition: form-data; name='file'; filename='ftp.txt' \r\n Content-Type: application/octet-stream \r\n open 127.0.0.1 21
anonymous
anonymous
bin
put file-to-upload.txt
quit
 \r\n --96985b62-451a-41fa-9eca-617e3599797c-- \r\nHTTP/1.1 200 OK
Date: Sat, 02 Jan 2021 22:11:03 GMT
Server: Apache/2.4.46 (Debian)
Content-Length: 0
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=UTF-8

© www.soinside.com 2019 - 2024. All rights reserved.