У меня есть URL, содержащий несколько символов косой черты (/
) в качестве части имени файла (а не URL-адреса). Но когда я отправляю HTTP-запрос, процент-кодированный %2F
переводится на /
перед отправкой запроса, поэтому генерирует неправильный URL-адрес.
Как сделать литеральный HTTP-запрос, игнорируя процентные значения в PowerShell?
Используется фактический URL (Chromium browser):
Я пробовал Invoke-WebRequest
cmdlet:
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`
Не найдена ошибка.
Также попробовал WebClient
DownloadFile
метод:
$wclient = New-Object System.Net.WebClient
$wclient.DownloadFile($ChromeUrl, $FilePath)
Возвращает 404 из-за неправильного запрошенного URL.
Обходной путь 1 (успешно)
Обходные решения, основанные на рефлексии, предоставляемые briantist и Tanuj 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
Обходной путь 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>
Соответствующие изменения должны быть выполнены в 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
Обходной путь 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
Временное решение 5 (не реализовано)
Единственный способ, которым я нашел правильный URL-адрес для запросов, - через экземпляр Internet Explorer.
$ie = New-Object -ComObject InternetExplorer.Application
$ie.Visible = $true
$ie.Silent = $false
$ie.Navigate2($ChromeUrl)
Но тогда я не знаю, как автоматизировать нажатие кнопки "Сохранить как" и сохранить ее на нужный путь. Кроме того, даже если это реализовано, я не чувствую, что это хорошее решение. Что происходит, когда IE уже запущен или удален из системы?