为什么 Invoke-WebRequest 和 Invoke-RestMethod 同时失败并成功? [英] Why is Invoke-WebRequest and Invoke-RestMethod failing and succeeding at the same time?

查看:53
本文介绍了为什么 Invoke-WebRequest 和 Invoke-RestMethod 同时失败并成功?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I wrote a small PowerShell script to send a request to a server and get a simple XML result back.

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 : 值不能为空.参数名称:名称.奇怪的是,当我用 Wireshark 监视它时,我看到了连接,看到了 POST 并且看到了来自服务器的结果,一切看起来都很好,但是cmdlet 说它失败了(是的,返回码是 200).

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. The error returned is 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).

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

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; -OutVariable fails just in case you're wondering.

结果是一个 xml 文件,标题指定它是 xml 并且 xml 格式正确.

The result is an xml file, the headers specify that it is xml and the xml is properly formatted.

成功时的结果

<?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 中看到脚本和服务器之间的正确对话.

Does anyone know why the Invoke-XXX cmdlets are returning an error and what I can do to fix it? 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.

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

Also, if I use -Verbose it tells me the following:

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 有效负载.

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

推荐答案

我继续研究了 Invoke-WebRequest cmdlet 代码,并找出了为什么它因这个特定错误而失败.

I went ahead and looked into the Invoke-WebRequest cmdlet code and found out why it's failing with this particular error.

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

It's failing on a call to 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. In the case of this server the Content-Type was sent back in the response as Content-Type: application/xml; charset="UTF-8".

这样做的问题是引号不是将值包装在 charset 中的标准,因此 cmdlet 将其解析为 "UTF-8" 而不是有效的UTF-8.该 cmdlet 将 "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. The cmdlet passes "UTF-8" to the function and the function throws an exception stating that the provided encoding is invalid. This is fine and would make so much more sense if that is what was reported in the final exception but it's not.

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

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

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

The call to GetEncoding inside the catch statement triggers the following code inside GetCodePageFromName which is itself called from GetEncoding

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

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

PowerShell is handling this properly since technically it is an invalid value but you'd think they would call Trim("\"") just to be safe.

这篇关于为什么 Invoke-WebRequest 和 Invoke-RestMethod 同时失败并成功?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆