【问题标题】:How to use GET method of Invoke-WebRequest to build a query string如何使用 Invoke-WebRequest 的 GET 方法构建查询字符串
【发布时间】:2015-12-03 06:02:51
【问题描述】:

是否有一种标准方法可以在 PowerShell 中使用 Invoke-WebRequest 或 Invoke-RestMethod 使用查询字符串从网页获取信息?

例如,我知道以下内容与格式良好的 JSON 端点一起使用时会起作用:

$Parameters = @{
  Name = 'John'
  Children = 'Abe','Karen','Jo'
}
$Result = Invoke-WebRequest -Uri 'http://.....whatever' -Body ( $Parameters | ConvertTo-Json)  -ContentType application/json -Method Get

以及等效的 Invoke-WebMethod。其中一个重要方面是内容类型和 ConvertTo-JSON,它管理将 -Body 部分中指定的参数转换为标准形式,包括“Children”字段的数组方面。

对于使用逗号分隔的约定来管理 URL 中的数组参数或诸如“Children[]=Abe&Children[]=Karen&Children=Jo”之类的方法的网站,有什么等效方法可以做到这一点?

是否有我缺少的内容类型,是否有等效的 ConvertTo-?我可以使用吗?我的猜测是以前有人必须这样做。

对于上下文,这是一个经常使用的 在 URL 中编码数组参数的方式,常见于 PHP 网站。

passing arrays as url parameter

编辑 除特定上下文外,删除了对 PHP 的引用,并调整了标题以引用查询字符串。问题在于编码查询字符串而不是 PHP 本身。

【问题讨论】:

  • 根据 HTTP/1.1 规范:GET 请求 = 无服务器端正文解析。将 GET 请求与请求正文相结合是没有意义的。
  • 我不确定 Invoke-WebRequest 在幕后做了什么,您对命名法无疑是正确的,但在上述用例中,它将使用标准 GET 查询对 URL 进行编码,例如http://...../?Name=John 在上面的例子中 - 虽然它构建数组参数的方式尚不清楚。数组构建是我的问题的症结所在。
  • 我明白了。我认为找出答案的最简单方法是破解 NetMon 或 WireShark 并查看通过网络发送的内容

标签: arrays json powershell


【解决方案1】:

似乎运行PHP的服务器在这里无关紧要。我想您是在问如何将键/值对作为查询字符串参数发送。

简单案例

如果是这样的话,你很幸运。 Invoke-RestMethodInvoke-WebRequest 都将在正文中使用 [hashtable] 并为您构造查询字符串:

$Parameters = @{
    Name = 'John'
    Children = 'Abe','Karen','Jo'
}
Invoke-WebRequest -Uri 'http://www.example.com/somepage.php' -Body $Parameters -Method Get # <-- optional, Get is the default

传递复杂对象

现在看到问题是您希望查询字符串参数具有多个值,本质上是一个数组,这排除了您可以传递给 body 参数的数据类型。

因此,让我们先从[UriBuilder] 对象开始逐个构建URI,然后添加使用[HttpValueCollection] 对象构建的查询字符串(允许重复键)。

$Parameters = [System.Web.HttpUtility]::ParseQueryString([String]::Empty)
$Parameters['Name'] = 'John'
foreach($Child in @('Abe','Karen','Joe')) {
    $Parameters.Add('Children', $Child)
}

$Request = [System.UriBuilder]'http://www.example.com/somepage.php'

$Request.Query = $Parameters.ToString()

Invoke-WebRequest -Uri $Request.Uri -Method Get # <-- optional, Get is the default

【讨论】:

  • 这将导致 uri-query 看起来像 "?Name=John&amp;Children=System.Object[]" :\
  • 谢谢,我会调查此事。我已经编辑了我的问题,以便更清楚地说明我关心的是构建查询字符串。
  • @briantist 谢谢,那行得通。我已经开始发布一个接近我正在寻找的答案。理想情况下,我想使用 PS 哈希表并将它们即时转换为 HTTP 查询字符串。你的指针显示了如何做到这一点。
  • 不幸的是,Invoke-RestMethodInvoke-WebRequest 都不对给定哈希表中的值进行 URL 编码,这使得该功能实际上完全无用。 [HttpValueCollection] 的方法要好得多。
【解决方案2】:

以下似乎作为“第一次切割”工作得相当好。感谢@briantist 提供了使用.NET HttpValueCollection 的关键点。看来我们必须“滚动我们自己”的方式来构建查询字符串。

下面的代码片段显示了一种简单的方法,通过简单地遍历哈希表,将包含参数和值的哈希表转换为格式良好的查询字符串。一个限制是不允许嵌套(参数值不能是复杂类型,例如哈希表)。

# Setup, parameters is now a PowerShell hash table
# we convert that on the fly to an appropriate URL
$Parameters = @{
    Name = 'John'
    Children = 'Abe','Karen','Jo'
}
$Uri = 'http://example.com/somepage.php'
$AddSquareBracketsToArrayParameters = $true



$HttpValueCollection = [System.Web.HttpUtility]::ParseQueryString([String]::Empty)
foreach ($Item in $Parameters.GetEnumerator()) {
    if ($Item.Value.Count -gt 1) {
        # It is an array, so treat that as a special case.
        foreach ($Value in $Item.Value) {
            # Add each item in the array, optionally mark the name of the parameter
            # to indicate it is an array parameter.
            $ParameterName = $Item.Key
            if ($AddSquareBracketsToArrayParameters) { $ParameterName += '[]' }                 
            $HttpValueCollection.Add($ParameterName, $Value)
        }
    } else {
        # Add the scalar value.
        $HttpValueCollection.Add($Item.Key,$Item.Value)
    }
}
# Build the request and load it with the query string.
$Request  = [System.UriBuilder]($Uri)
$Request.Query = $HttpValueCollection.ToString()

# Now fire off the request.
Invoke-WebRequest -Uri $Request.Uri

【讨论】:

  • 酷,只是想指出另一种检查值是否为数组的方法是执行以下操作:if ($Item.Value -is [Array]) { }
  • @briantist 感谢它看起来更干净。它还会为单个元素的数组提供正确的行为吗?
  • 取决于正确行为的含义。如果它确实是一个包含一个元素的数组,它将返回true。如果不是,它将返回 false。 @('a') -is [Array] 应该返回 true'a' -is [Array]: false.
  • 我应该更明确一点。我指的行为是在服务器端。如果服务器期望单个字段(单位长度的数组)被称为“FieldName”,但它最终被称为“FieldName []”,因为它被视为可能导致麻烦的数组(尽管是单位长度)。我不确定这一点,因为它可能取决于服务器端脚本。
  • 对我来说,您在查询字符串中用于数组的[] 语法看起来很奇怪。我从来没有见过这样的事情。通常我所看到的是,键在查询字符串中多次出现,具有不同的值(我发布的答案会以这种方式产生一个查询字符串),如?Key1=Something&amp;Key2=ThingA&amp;Key2=ThingB&amp;Key2=ThingC
猜你喜欢
  • 2014-11-18
  • 2020-10-26
  • 2010-09-23
  • 1970-01-01
  • 2012-01-17
  • 2018-07-28
  • 2014-08-09
  • 2013-05-30
相关资源
最近更新 更多