Powershell - 将 WebRequest 调用到 URL,其中包含文字“/”(%2F)
Powershell - Invoke-WebRequest to a URL with literal '/' (%2F) in it
我一直在尝试使用以下命令从 powershell 访问其中包含 /
字符的 URL(这是对 gitlab 服务器的查询,以检索名为 [=16 的项目=]):
Invoke-WebRequest https://server.com/api/v3/projects/foo%2Fbar -Verbose
现在,奇怪的是使用 PowerShell ISE 或 Visual Studio,请求是正常的。使用 PowerShell 本身时,URL 会自动取消转义并且请求失败。
例如。
在ISE/VS中:
$> Invoke-WebRequest https://server.com/api/v3/projects/foo%2Fbar -Verbose
VERBOSE: GET https://server.com/api/v3/projects/foo%2Fbar with 0-byte payload
VERBOSE: received 19903-byte response of content type application/json
StatusCode : 200
StatusDescription : OK
Content : .... data ....
在 Powershell 中:
$> Invoke-WebRequest https://server.com/api/v3/projects/foo%2Fbar -Verbose
VERBOSE: GET https://server.com/api/v3/projects/foo/bar with 0-byte payload
Invoke-WebRequest : {"error":"404 Not Found"}
At line:1 char:1
+ Invoke-WebRequest 'https://server.com/api/v3/projects/foo%2Fbar ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
我尝试在 URL 周围添加单引号和双引号,但没有任何帮助。
这种行为的原因是什么,我如何使 PS 不取消转义 URL 字符串?
环境:Windows7,也在Server 2012R2上测试,结果相同。
$> $PSVersionTable
Name Value
---- -----
PSVersion 4.0
WSManStackVersion 3.0
SerializationVersion 1.1.0.1
CLRVersion 4.0.30319.42000
BuildVersion 6.3.9600.16406
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0}
PSRemotingProtocolVersion 2.2
通过此功能尝试URL
function fixuri($uri){
$UnEscapeDotsAndSlashes = 0x2000000;
$SimpleUserSyntax = 0x20000;
$type = $uri.GetType();
$fieldInfo = $type.GetField("m_Syntax", ([System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic));
$uriParser = $fieldInfo.GetValue($uri);
$typeUriParser = $uriParser.GetType().BaseType;
$fieldInfo = $typeUriParser.GetField("m_Flags", ([System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::FlattenHierarchy));
$uriSyntaxFlags = $fieldInfo.GetValue($uriParser);
$uriSyntaxFlags = $uriSyntaxFlags -band (-bnot $UnEscapeDotsAndSlashes);
$uriSyntaxFlags = $uriSyntaxFlags -band (-bnot $SimpleUserSyntax);
$fieldInfo.SetValue($uriParser, $uriSyntaxFlags);
}
$uri = New-Object System.Uri -ArgumentList ("https://server.com/api/v3/projects/foo%2Fbar")
fixuri $uri
我在 PowerShell 5.1 中遇到过类似的问题。我的目的是通过 Git Lab Web API 获得一个项目。正如网络 API 所述:
Get single project
Get a specific project, identified by project ID or NAMESPACE/PROJECT_NAME , which is owned by the authentication user.
If using namespaced projects call make sure that the NAMESPACE/PROJECT_NAME is URL-encoded, eg. /api/v3/projects/diaspora%2Fdiaspora (where / is represented by %2F).
nik 的不同之处在于,我的 Invoke-WebRequest 调用通过直接调用成功,但在作业中失败。这是代码:
Start-Job -ScriptBlock {
try{
Invoke-WebRequest https://server.com/api/v3/projects/foo%2Fbar -verbose
} catch {
Write-Output $_.Exception
}
}
获取作业中的输出。 运行 命令:
> Get-Job | Receive-Job -Keep
例外情况如下:
VERBOSE: GET https://server.com/api/v3/projects/foo/bar with 0-byte payload
System.Net.WebException: The remote server returned an error: (404) Not Found.
at Microsoft.PowerShell.Commands.WebRequestPSCmdlet.GetResponse(WebRequest request)
at Microsoft.PowerShell.Commands.WebRequestPSCmdlet.ProcessRecord()
感谢 Oleg SH 的回答。我的问题解决了。但我认为 Start-Job cmdlet 中可能存在错误
环境:Windows7
>$PSVersionTable
Name Value
---- -----
PSVersion 5.1.14409.1005
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.14409.1005
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
这是 的备用端口 - 它接受一个字符串和 returns 一个新的 URI。
function CreateUriWithoutIncorrectSlashEncoding {
param(
[Parameter(Mandatory)][string]$uri
)
$newUri = New-Object System.Uri $uri
[void]$newUri.PathAndQuery # need to access PathAndQuery (presumably modifies internal state)
$flagsFieldInfo = $newUri.GetType().GetField("m_Flags", [System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic)
$flags = $flagsFieldInfo.GetValue($newUri)
$flags = $flags -band (-bnot 0x30) # remove Flags.PathNotCanonical|Flags.QueryNotCanonical (private enum)
$flagsFieldInfo.SetValue($newUri, $flags)
$newUri
}
用法:
$uri = CreateUriWithoutIncorrectSlashEncoding "https://server.com/api/v3/projects/foo%2Fbar"
我一直在尝试使用以下命令从 powershell 访问其中包含 /
字符的 URL(这是对 gitlab 服务器的查询,以检索名为 [=16 的项目=]):
Invoke-WebRequest https://server.com/api/v3/projects/foo%2Fbar -Verbose
现在,奇怪的是使用 PowerShell ISE 或 Visual Studio,请求是正常的。使用 PowerShell 本身时,URL 会自动取消转义并且请求失败。 例如。
在ISE/VS中:
$> Invoke-WebRequest https://server.com/api/v3/projects/foo%2Fbar -Verbose
VERBOSE: GET https://server.com/api/v3/projects/foo%2Fbar with 0-byte payload
VERBOSE: received 19903-byte response of content type application/json
StatusCode : 200
StatusDescription : OK
Content : .... data ....
在 Powershell 中:
$> Invoke-WebRequest https://server.com/api/v3/projects/foo%2Fbar -Verbose
VERBOSE: GET https://server.com/api/v3/projects/foo/bar with 0-byte payload
Invoke-WebRequest : {"error":"404 Not Found"}
At line:1 char:1
+ Invoke-WebRequest 'https://server.com/api/v3/projects/foo%2Fbar ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
我尝试在 URL 周围添加单引号和双引号,但没有任何帮助。
这种行为的原因是什么,我如何使 PS 不取消转义 URL 字符串?
环境:Windows7,也在Server 2012R2上测试,结果相同。
$> $PSVersionTable
Name Value
---- -----
PSVersion 4.0
WSManStackVersion 3.0
SerializationVersion 1.1.0.1
CLRVersion 4.0.30319.42000
BuildVersion 6.3.9600.16406
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0}
PSRemotingProtocolVersion 2.2
通过此功能尝试URL
function fixuri($uri){
$UnEscapeDotsAndSlashes = 0x2000000;
$SimpleUserSyntax = 0x20000;
$type = $uri.GetType();
$fieldInfo = $type.GetField("m_Syntax", ([System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic));
$uriParser = $fieldInfo.GetValue($uri);
$typeUriParser = $uriParser.GetType().BaseType;
$fieldInfo = $typeUriParser.GetField("m_Flags", ([System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::FlattenHierarchy));
$uriSyntaxFlags = $fieldInfo.GetValue($uriParser);
$uriSyntaxFlags = $uriSyntaxFlags -band (-bnot $UnEscapeDotsAndSlashes);
$uriSyntaxFlags = $uriSyntaxFlags -band (-bnot $SimpleUserSyntax);
$fieldInfo.SetValue($uriParser, $uriSyntaxFlags);
}
$uri = New-Object System.Uri -ArgumentList ("https://server.com/api/v3/projects/foo%2Fbar")
fixuri $uri
我在 PowerShell 5.1 中遇到过类似的问题。我的目的是通过 Git Lab Web API 获得一个项目。正如网络 API 所述:
Get single project
Get a specific project, identified by project ID or NAMESPACE/PROJECT_NAME , which is owned by the authentication user. If using namespaced projects call make sure that the NAMESPACE/PROJECT_NAME is URL-encoded, eg. /api/v3/projects/diaspora%2Fdiaspora (where / is represented by %2F).
nik 的不同之处在于,我的 Invoke-WebRequest 调用通过直接调用成功,但在作业中失败。这是代码:
Start-Job -ScriptBlock {
try{
Invoke-WebRequest https://server.com/api/v3/projects/foo%2Fbar -verbose
} catch {
Write-Output $_.Exception
}
}
获取作业中的输出。 运行 命令:
> Get-Job | Receive-Job -Keep
例外情况如下:
VERBOSE: GET https://server.com/api/v3/projects/foo/bar with 0-byte payload
System.Net.WebException: The remote server returned an error: (404) Not Found.
at Microsoft.PowerShell.Commands.WebRequestPSCmdlet.GetResponse(WebRequest request)
at Microsoft.PowerShell.Commands.WebRequestPSCmdlet.ProcessRecord()
感谢 Oleg SH 的回答。我的问题解决了。但我认为 Start-Job cmdlet 中可能存在错误
环境:Windows7
>$PSVersionTable
Name Value
---- -----
PSVersion 5.1.14409.1005
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.14409.1005
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
这是 的备用端口 - 它接受一个字符串和 returns 一个新的 URI。
function CreateUriWithoutIncorrectSlashEncoding {
param(
[Parameter(Mandatory)][string]$uri
)
$newUri = New-Object System.Uri $uri
[void]$newUri.PathAndQuery # need to access PathAndQuery (presumably modifies internal state)
$flagsFieldInfo = $newUri.GetType().GetField("m_Flags", [System.Reflection.BindingFlags]::Instance -bor [System.Reflection.BindingFlags]::NonPublic)
$flags = $flagsFieldInfo.GetValue($newUri)
$flags = $flags -band (-bnot 0x30) # remove Flags.PathNotCanonical|Flags.QueryNotCanonical (private enum)
$flagsFieldInfo.SetValue($newUri, $flags)
$newUri
}
用法:
$uri = CreateUriWithoutIncorrectSlashEncoding "https://server.com/api/v3/projects/foo%2Fbar"