在请求分派之前解码百分比编码的斜杠("/")

naz*_*kus 13 .net url powershell uri

我有一个URL包含几个斜杠字符(/)作为文件名的一部分(而不是URL).但是当我发送http请求时,百分比编码%2F被转换为/请求分派之前,因此生成错误的URL.

如何在PowerShell中创建一个忽略百分比编码值的文字http请求?

使用的实际网址(Chromium浏览器):

https://www.googleapis.com/download/storage/v1/b/chromium-browser-continuous/o/Win_x64%2F292817%2Fchrome-win32.zip?generation=1409504089694000&alt=media


我试过Invoke-WebRequestcmdlet:

Invoke-WebRequest -Uri $ChromeUrl -OutFile $FilePath -Verbose

VERBOSE: GET https://www.googleapis.com/download/storage/v1/b/chromium-browser-continuous/o/Win_x64/292817/chrome-win32.zip?generation=1409504089694000&alt=media with 0-byte payload1`
Run Code Online (Sandbox Code Playgroud)

找不到错误.

还试过WebClientDownloadFile方法:

$wclient = New-Object System.Net.WebClient
$wclient.DownloadFile($ChromeUrl, $FilePath)
Run Code Online (Sandbox Code Playgroud)

由于再次请求错误的URL而返回404.


解决方法1(成功)

briantistTanuj Mathur提供的基于反射的解决方法都很有效.后者:

$UrlFixSrc = @" 
using System;
using System.Reflection;

public static class URLFix 
{ 
    public static void ForceCanonicalPathAndQuery(Uri uri)
    {
        string paq = uri.PathAndQuery;
        FieldInfo flagsFieldInfo = typeof(Uri).GetField("m_Flags", BindingFlags.Instance | BindingFlags.NonPublic);
        ulong flags = (ulong) flagsFieldInfo.GetValue(uri);
        flags &= ~((ulong) 0x30);
        flagsFieldInfo.SetValue(uri, flags);
    }
} 
"@ 

Add-Type -TypeDefinition $UrlFixSrc-Language CSharp
[URLFix]::ForceCanonicalPathAndQuery([URI]$ChromeUrl)

Invoke-WebRequest -Uri $ChromeUrl -OutFile $FilePath -Verbose

VERBOSE: GET https://www.googleapis.com/download/storage/v1/b/chromium-browser-continuous/o/Win_x64%2F292640%2Fchrome-win32.zip?generation=1409351584147000&alt=media
Run Code Online (Sandbox Code Playgroud)

解决方法2(成功)

更简洁的解决方案(由Tanuj Mathur提供),但需要访问系统文件,是通过添加%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe.config包含以下内容的配置文件:

<?xml version="1.0" encoding="utf-8" ?> 
 <configuration> 
   <uri>
     <schemeSettings>
      <add name="http" genericUriParserOptions="DontUnescapePathDotsAndSlashes" />
      <add name="https" genericUriParserOptions="DontUnescapePathDotsAndSlashes" />
     </schemeSettings>
   </uri>
</configuration>
Run Code Online (Sandbox Code Playgroud)

必须进行相应的修改才能powerhsell_ise.exe.config在ISE中工作.

解决方法3(失败)

我认为它是一个System.URI类隐式转换调用的类构造函数问题,它会转换转义值.试过一个重载的变种Uri ([String]uriString, [Boolean]dontEscape).但没有区别.有或没有dontEscape争论的结果相同.

$uri = new-object System.Uri($ChromeUrl, $true)
$uri | Format-List OriginalString, AbsoluteUri

  OriginalString : https://www.googleapis.com/download/storage/v1/b/chromium-browser-continuous/o/Win_x64%2F292817%2Fchrome-win32.zip?generation=1409504089694000&alt=media
  AbsoluteUri    : https://www.googleapis.com/download/storage/v1/b/chromium-browser-continuous/o/Win_x64/292817/chrome-win32.zip?generation=1409504089694000&alt=media
Run Code Online (Sandbox Code Playgroud)

解决方法4(失败)

还试图通过用百分比编码的值替换百分号来欺骗URI解析器%25.但后来它完全忽略了一切.

Invoke-WebRequest -Uri $ChromeUrl.Replace('%', '%25') -OutFile $DownloadPath -Verbose

VERBOSE: GET https://www.googleapis.com/download/storage/v1/b/chromium-browser-continuous/o/Win_x64%252F292817%252Fchrome-win32.zip?generation=1409504089694000&alt=media with 0-byte pa yload
Run Code Online (Sandbox Code Playgroud)

解决方法5(未实施)

我发现请求URL正确的唯一方法是通过Internet Explorer实例.

$ie = New-Object -ComObject InternetExplorer.Application                
$ie.Visible = $true
$ie.Silent = $false
$ie.Navigate2($ChromeUrl)
Run Code Online (Sandbox Code Playgroud)

但后来我不知道如何自动化"另存为"按钮单击并将其保存到所需的路径.此外,即使实施,我也不认为这是一个很好的解决方案.当IE已经从系统运行或卸载时会发生什么?

Tan*_*hur 8

在过去的几个小时里,我一直在玩你的代码,这是一个很糟糕的事情.在Powershell ISE中运行时,给定的代码及其变体都会通过,但在Powershell控制台上失败.问题本身似乎是Microsoft Connect在此处记录的问题.

有趣的是,根据用户Glenn Block 对相关问题回答,这个错误在.NET Framework 4.5中得到了修复.您可以通过运行命令来检查Powershell正在使用的.NET框架的版本$PSVersionTable.只要CLRVersion值为4.0.30319.x,其中x> 1700,那么您运行的是框架的v4.5.

我在我的机器上运行.NET Framework 4.5上的Powershell v4.0,这解释了为什么Powershell ISE显示正确的行为,但我无法弄清楚为什么Powershell控制台没有.我验证了两者加载的.NET程序集,它们似乎是相同的.

事实上,我们有两种选择.一种是使用反射并在.Net类上设置一个私有字段来防止这种行为(如本答案中所述).另一种方法是使用Microsoft Connect问题中列出的解决方法.这涉及以下步骤:

  1. 转到您的Powershell安装文件夹(这"C:\Windows\System32\WindowsPowerShell\v1.0\"在我的机器上).该文件夹中应包含该文件powershell.exe.
  2. 在此文件夹中创建一个新文本文件,并为其命名 powershell.exe.config
  3. 在文本编辑器中打开此文件,并将以下文本粘贴到其中: <?xml version="1.0" encoding="utf-8" ?> <configuration> <uri> <schemeSettings> <add name="http" genericUriParserOptions="DontUnescapePathDotsAndSlashes" /> <add name="https" genericUriParserOptions="DontUnescapePathDotsAndSlashes" /> </schemeSettings> </uri> </configuration>

  4. 保存此文件.关闭所有正在运行的Powershell实例.

  5. 启动Powershell的新实例.这将导致Powershell检测您创建的配置文件并解析它.配置条目基本上告诉.NET库禁用HTTP和HTTPS uri的自动转义.
  6. 运行你的脚本.您不应再看到Uris的问题.