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

时间:2016-03-29 04:43:43

标签: powershell

我编写了一个小型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)。

如果我使用Invoke-WebRequest参数运行Invoke-RestMethod / -OutFile,它运行正常且没有错误,并将结果保存到指定的文件中;如果您想知道,-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有效负载,这很奇怪。

1 个答案:

答案 0 :(得分:9)

我继续查看Invoke-WebRequest cmdlet代码,找出了导致此特定错误失败的原因。

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

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

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

<强> Microsoft.PowerShell.Commands.ContentHelper.GetEncodingOrDefault

name

对catch语句中的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); } } 的调用会触发GetEncoding中的以下代码,该代码本身从GetCodePageFromName

调用
GetEncoding

PowerShell正在正确处理此问题,因为从技术上讲,它是一个无效的值,但您认为他们只是为了安全而致电if (name==null) { throw new ArgumentNullException("name"); }