繁体   English   中英

为什么 Invoke-WebRequest 和 Invoke-RestMethod 同时失败和成功?

[英]Why is Invoke-WebRequest and Invoke-RestMethod failing and succeeding at the same time?

我写了一个小的 PowerShell 脚本来向服务器发送请求并返回一个简单的 XML 结果。

PowerShell 脚本

$xml = "<?xml version='1.0' encoding='utf-8'?><Search><ID>278A87E1-1BC2-4E19-82E9-8BBE31D67D20</ID></Search>"
$response = Invoke-RestMethod -Method Post -Uri "http://localhost/search" -ContentType "application/xml" -Body $xml

就是这样,非常简单,我没有理由认为它会失败。 我还尝试了使用Invoke-WebRequest的脚本,但都失败了。 返回的错误是Invoke-RestMethod: Value cannot be null. Parameter name: name 奇怪的是,当我用Wireshark监视它时,我看到了连接,我看到了POST ,我看到了来自服务器的结果,一切看起来都很好,但是 cmdlet 说它失败了(是的,返回码是 200 ).

如果我使用-OutFile参数运行Invoke-WebRequest / Invoke-RestMethod ,它运行良好且没有错误并将结果保存到指定文件; -OutVariable失败以防万一你想知道。

结果是一个 xml 文件,标头指定它是 xml 并且 xml 的格式正确。

成功时的结果

<?xml version="1.0" encoding="UTF-8" ?>
<Result version="1.0" xmlns="urn:xmlns-org">
    <searchID>{278a87e1-1bc2-4e19-82e9-8bbe31d67d20}</searchID>
    <responseStatus>true</responseStatus>
    <responseStatusStrg>MORE</responseStatusStrg>
    <numOfMatches>40</numOfMatches>
</Result>

有谁知道为什么Invoke-XXX cmdlet 返回错误以及我可以做些什么来修复它? 同样,当我使用-OutFile参数时,它工作得很好,即使它失败了,我也可以在Wireshark中看到脚本和服务器之间的正确对话。

另外,如果我使用-Verbose它会告诉我以下内容:

VERBOSE: POST http://localhost/search with -1-byte payload
VERBOSE: received X-byte response of content type application/xml; charset="UTF-8"

其中X-byte是响应的实际大小,但根据发送到服务器的数据,每个响应明显不同。 我只是觉得 cmdlet 失败但说它收到了一个包含数据的响应并且它发送了一个-1-byte有效负载,这很奇怪。

我继续查看了Invoke-WebRequest cmdlet代码,并找出了为什么它失败了这个特定的错误。

它在调用System.Globalization.EncodingTable.GetCodePageFromName失败了。 编码作为参数传递给该函数,并通过Content-Type标头从cmdlet中检索编码。 在此服务器的情况下,Content-Type在响应中作为Content-Type: application/xml; charset="UTF-8"发送回Content-Type: application/xml; charset="UTF-8" Content-Type: application/xml; charset="UTF-8"

这样做的问题是引号不是标准用于在charset包装值,因此cmdlet将其解析为"UTF-8"而不是有效的UTF-8 cmdlet将"UTF-8"传递给函数,该函数抛出一个异常,指出提供的编码无效。 这很好,并且如果这是最终例外中报告的内容会更有意义,但事实并非如此。

Microsoft.PowerShell.Commands.ContentHelper.GetEncodingOrDefault函数捕获无效编码异常,并在异常处理程序中再次调用GetEncoding但使用null参数导致参数name的最终ArgumentNullException

Microsoft.PowerShell.Commands.ContentHelper.GetEncodingOrDefault

internal static Encoding GetEncodingOrDefault(string characterSet)
{
  string name = string.IsNullOrEmpty(characterSet) ? "ISO-8859-1" : characterSet;
  try
  {
    return Encoding.GetEncoding(name);
  }
  catch (ArgumentException ex)
  {
    return Encoding.GetEncoding((string) null);
  }
}

在catch语句中调用GetEncoding会触发GetCodePageFromName的以下代码,该代码本身是从GetEncoding

if (name==null) { 
    throw new ArgumentNullException("name");
}

PowerShell正在处理这个问题,因为从技术上讲它是一个无效的值,但你认为他们会调用Trim("\\"")只是为了安全。

虽然这个线程已有多年历史,但我是在 2022 年遇到同样的错误“Invoke-RestMethod: Value cannot be null. Parameter name: name”访问 API 以创建用户时遇到的。 在我的例子中,Content-Type 是application/json (而不是上面 Vane 的问题中的application/xml )。 API POST 需要基本身份验证。

在转换为 Base64 之前,我对凭据进行了 UTF8 编码,结果错误消失了。 鉴于上面 Vane 的 Content-Type 调查跟踪了charset="UTF-8"的返回,这个 UTF8 编码和错误的消失可能是相关的,尽管这只是我的猜测。

$username = "your_username"
$password = "your_password"
$credential = "${username}:${password}"
$credentialBytes = [System.Text.Encoding]::UTF8.GetBytes($credential)
$encodedCredential = [System.Convert]::ToBase64String($credentialBytes)
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Authorization", "Basic $encodedCredential")
$headers.Add("Content-Type", "application/json")

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM