简体   繁体   English

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

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

I wrote a small PowerShell script to send a request to a server and get a simple XML result back.我写了一个小的 PowerShell 脚本来向服务器发送请求并返回一个简单的 XML 结果。

PowerShell Script 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

That's it, really simple and there's no reason that I can see for it to be failing.就是这样,非常简单,我没有理由认为它会失败。 I have also tried the script with Invoke-WebRequest and both fail.我还尝试了使用Invoke-WebRequest的脚本,但都失败了。 The error returned is Invoke-RestMethod: Value cannot be null. Parameter name: name .返回的错误是Invoke-RestMethod: Value cannot be null. Parameter name: name The strange thing is that when I monitor this with Wireshark , I see the connection, I see the POST and I see the result from the server and all looks perfectly good but the cmdlet is saying it failed (and yes, the return code is 200).奇怪的是,当我用Wireshark监视它时,我看到了连接,我看到了POST ,我看到了来自服务器的结果,一切看起来都很好,但是 cmdlet 说它失败了(是的,返回码是 200 ).

If I run the Invoke-WebRequest / Invoke-RestMethod with the -OutFile parameter, it runs fine with no errors and saves the result to the specified file;如果我使用-OutFile参数运行Invoke-WebRequest / Invoke-RestMethod ,它运行良好且没有错误并将结果保存到指定文件; -OutVariable fails just in case you're wondering. -OutVariable失败以防万一你想知道。

The result is an xml file, the headers specify that it is xml and the xml is properly formatted.结果是一个 xml 文件,标头指定它是 xml 并且 xml 的格式正确。

Result when successful成功时的结果

<?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>

Does anyone know why the Invoke-XXX cmdlets are returning an error and what I can do to fix it?有谁知道为什么Invoke-XXX cmdlet 返回错误以及我可以做些什么来修复它? Again, it works perfectly fine when I use the -OutFile parameter and even when it fails I can see a proper conversation between the script and the server in Wireshark .同样,当我使用-OutFile参数时,它工作得很好,即使它失败了,我也可以在Wireshark中看到脚本和服务器之间的正确对话。

Also, if I use -Verbose it tells me the following:另外,如果我使用-Verbose它会告诉我以下内容:

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

Where X-byte is the actual size of the response but it obviously differs with each response depending on the data sent to the server.其中X-byte是响应的实际大小,但根据发送到服务器的数据,每个响应明显不同。 I just find it odd that the cmdlet fails but says it received a response with data and that it sent a -1-byte payload.我只是觉得 cmdlet 失败但说它收到了一个包含数据的响应并且它发送了一个-1-byte有效负载,这很奇怪。

I went ahead and looked into the Invoke-WebRequest cmdlet code and found out why it's failing with this particular error. 我继续查看了Invoke-WebRequest cmdlet代码,并找出了为什么它失败了这个特定的错误。

It's failing on a call to System.Globalization.EncodingTable.GetCodePageFromName . 它在调用System.Globalization.EncodingTable.GetCodePageFromName失败了。 The encoding is passed to that function as a parameter and the encoding is retrieved from the the cmdlet through the Content-Type header. 编码作为参数传递给该函数,并通过Content-Type标头从cmdlet中检索编码。 In the case of this server the Content-Type was sent back in the response as Content-Type: application/xml; charset="UTF-8" 在此服务器的情况下,Content-Type在响应中作为Content-Type: application/xml; charset="UTF-8"发送回Content-Type: application/xml; charset="UTF-8" Content-Type: application/xml; charset="UTF-8" . Content-Type: application/xml; charset="UTF-8"

The problem with this is that quotes aren't standard for wrapping the value in charset so the cmdlet parses it out as "UTF-8" instead of the valid UTF-8 . 这样做的问题是引号不是标准用于在charset包装值,因此cmdlet将其解析为"UTF-8"而不是有效的UTF-8 The cmdlet passes "UTF-8" to the function and the function throws an exception stating that the provided encoding is invalid. cmdlet将"UTF-8"传递给函数,该函数抛出一个异常,指出提供的编码无效。 This is fine and would make so much more sense if that is what was reported in the final exception but it's not. 这很好,并且如果这是最终例外中报告的内容会更有意义,但事实并非如此。

The Invalid encoding exception is caught by the Microsoft.PowerShell.Commands.ContentHelper.GetEncodingOrDefault function and in the exception handler it calls GetEncoding again but with a null parameter which results in the final ArgumentNullException for parameter name . Microsoft.PowerShell.Commands.ContentHelper.GetEncodingOrDefault函数捕获无效编码异常,并在异常处理程序中再次调用GetEncoding但使用null参数导致参数name的最终ArgumentNullException

Microsoft.PowerShell.Commands.ContentHelper.GetEncodingOrDefault 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);
  }
}

The call to GetEncoding inside the catch statement triggers the following code inside GetCodePageFromName which is itself called from GetEncoding 在catch语句中调用GetEncoding会触发GetCodePageFromName的以下代码,该代码本身是从GetEncoding

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

PowerShell is handling this properly since technically it is an invalid value but you'd think they would call Trim("\\"") just to be safe. PowerShell正在处理这个问题,因为从技术上讲它是一个无效的值,但你认为他们会调用Trim("\\"")只是为了安全。

Although this thread is years-old, I came across it in 2022 when I encountered the same error 'Invoke-RestMethod: Value cannot be null. Parameter name: name' accessing an API to create a user.虽然这个线程已有多年历史,但我是在 2022 年遇到同样的错误“Invoke-RestMethod: Value cannot be null. Parameter name: name”访问 API 以创建用户时遇到的。 In my case Content-Type was application/json (rather than application/xml in Vane's question above).在我的例子中,Content-Type 是application/json (而不是上面 Vane 的问题中的application/xml )。 The API POST required Basic Auth. API POST 需要基本身份验证。

I UTF8 encoded the credentials prior to converting to Base64, and et voilà the error disappeared.在转换为 Base64 之前,我对凭据进行了 UTF8 编码,结果错误消失了。 Given that the Content-Type investigation by Vane above tracked a return of charset="UTF-8" , this UTF8 encoding and the disappearance of the error may be related, although this is just surmise on my part.鉴于上面 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