3

我正在使用 OneLogin REST API,并且似乎无法使用 PUT 方法进行任何调用。当我在 Postman 中进行测试时,我可以像这样传递一个原始 JSON 正文:

{
   "role_id_array":  [
                        115028
                     ]
}

到端点:

https://api.us.onelogin.com/api/1/users/ /add_roles

这工作得很好。但是,当我尝试对 PowerShell 的 Invoke-RestMethod 命令执行相同操作时,我收到 400 Bad Request 错误。我的代码如下所示:

$Splat = @{
    Method      = $Method
    Uri         = https://api.us.onelogin.com/api/1/users/12345678/add_roles
    ContentType = "application/json"
    Headers     = @{authorization = "bearer:$($Token.access_token)"}
    Body        = @{role_id_array = @(123456)}
}

Invoke-RestMethod @Splat

到目前为止,我对任何 GET 调用都没有问题,只有 PUT 调用。此外,如果我运行通过 ConvertTo-Json 传入的 Body 哈希表,输出看起来就像上面的工作示例。有人对为什么这不起作用有任何想法吗?

4

2 回答 2

9

我能够得到一个PUT工作!

如何从 Invoke-RestMethod 获取丰富的错误响应数据

首先,我在这里使用了这篇博Invoke-RestMethod文,它有一个很好的方法来检索一个或WebRequestcmdlet的完整错误消息。

在他的方法中,首先定义了一个Function,叫做Failure。

function Failure {
    $global:helpme = $body
    $global:helpmoref = $moref
    $global:result = $_.Exception.Response.GetResponseStream()
    $global:reader = New-Object System.IO.StreamReader($global:result)
    $global:responseBody = $global:reader.ReadToEnd();
    Write-Host -BackgroundColor:Black -ForegroundColor:Red "Status: A system exception was caught."
    Write-Host -BackgroundColor:Black -ForegroundColor:Red $global:responsebody
    Write-Host -BackgroundColor:Black -ForegroundColor:Red "The request body has been saved to `$global:helpme"
    break
}

然后,像这样将所有 Invoke-RestMethod 调用包装在 try Catch 块中。

try { 
    $e = Invoke-WebRequest 'https://api.us.onelogin.com/api/1/users/$id' `
        -Headers  @{ Authorization = "bearer:$token" } `
        -Body ( @{ phone = "7709746046" } | ConvertTo-Json ) `
        -Method Put `
        -ErrorAction:Stop `
        -ContentType 'application/json' 
} 
catch {Failure}

现在,当您遇到错误时,您可以看到实际消息,如下所示

> Status: A system exception was caught.
{"status":{"error":true,"code":400,"type":"bad request","message":{"description":"notes is not a valid attribute for user model","attribute":"notes"}}}
The request body has been saved to $global:helpme

这对帮助我摆脱遇到的错误非常有帮助,并且我能够使用PUT动词更新用户条目并使其正常工作。

解决您的问题

我只需要对您的代码进行两次更改即可使其正常工作。

首先,在 URI 周围加上引号,因为您的示例代码没有它们,而且您必须在哈希表中的字符串周围加上引号。

最后,将您的正文内容通过管道传输到ConvertTo-JSON,否则数据将作为字符串发送,就像您在 Fiddler 中找到的那样。

有了这两个更改,这是我的请求和响应

$Splat = @{
    Method      = 'PUT'
    Uri         = 'https://api.us.onelogin.com/api/1/users/27697924/add_roles'
    ContentType = "application/json"
    Headers     = @{authorization = "bearer:$token" }
    Body        = @{role_id_array = @(143175)} | ConvertTo-Json
}

try {Invoke-RestMethod @Splat -ErrorAction Stop }
catch {Failure}

这是回应:

status                                                 
------                                                 
@{type=success; message=Success; error=False; code=200}

更新:我们做到了,现在已经修复了!

如果你认为 PowerShell 应该为非 200 状态代码呈现实际的服务器响应,那么请帮助在 Github上的 PowerShell项目页面上引起对这个未解决问题的关注。

添加您的反馈或竖起大拇指,我们可能会在该语言的未来版本中对此进行更改。

从 PowerShell v6.1 开始,此问题现已修复

于 2016-09-06T03:20:18.680 回答
-1

好的,所以我崩溃并安装了 Fiddler,我想我正在做一些事情。PowerShell cmdlet 似乎不知道如何处理 application/json 内容类型的数组。我不确定 XML 是否会出现这种情况,因为我还没有测试过。

我将正文更改为使用直接的 json 字符串,它起作用了:

$Body = "{ `"role_id_array`": [123456] }"

如果我使用将值设置为这样的数组的哈希表:

$Body = @{role_id_array = 115028,128732}

然后我会得到一个 400 失败响应。Fiddler 向我展示了发生了什么 - 这是原始请求:

PUT https://api.us.onelogin.com/api/1/users/12345678/add_roles HTTP/1.1 授权:bearer:3c93ae2-redacted- 用户代理:Mozilla/5.0(Windows NT;Windows NT 6.3;en-美国)WindowsPowerShell/5.1.14394.1000 内容类型:application/json 主机:api.us.onelogin.com 内容长度:33 role_id_array=System.Object%5b%5d

请注意,数组没有正确转换,而是 Invoke-RestMethod 只是将其折叠到类型名称定义中,类似于 Export-Csv 处理数组属性值的方式。

所以我认为我在使用 PUT 方法时遇到了问题,因为我所有的 GET 调用都在工作,但这是一个红鲱鱼。真正的问题是处理一个 REST 端点,它的请求参数值需要数组值。

编辑:我发现其他人早在 2014 年就发布了这个问题,但他的解决方案是将 -ContentType 参数设置为“application/json”:

Powershell v4 Invoke-RestMethod 正文发送 System.Object

我已经这样做了,但仍然遇到同样的问题。这是一个错误吗?

于 2016-09-05T03:06:38.397 回答