1

我在Linux上使用PowerShell Core v6-beta.5使用AppImage。有沒有辦法找出301重定向的「新」位置?Powershell確定永久移動(重定向)資源的新URL

Invoke-WebRequest -Method HEAD http://SomethingThatThrows301.com/ -MaximumRedirection 0引發錯誤(Response status code does not indicate success: 301 (Moved Permanently))。

雖然錯誤確實提到移動是一個301,我仍然喜歡一個適當的對象告訴我,和新的地址。

有沒有辦法做到這一點?

回答

1

注:以下作品中的所有代碼均Windows PowerShell中PowerShell核心,所有支持的平臺上,有多達50個重定向默認。

假設:

  • ,你不關心具體的3xx重定向狀態代碼和
  • 要知道 最終目標URL
  • (有可能是一個重定向)

使用以下內容:

[System.Net.HttpWebRequest]::Create('http://cnn.com').GetResponse().ResponseUri.AbsoluteUri 

這個收益率(注意:目標URL如何有www.):

http://www.cnn.com 

下面是高級方便的功能Get-UrlRedirection,其中包功能的源代碼,同時提供分辨率最終目標URL和重定向URL鏈的枚舉。

調用示例:

> Get-UrlRedirection http://cnn.com 
http://www.cnn.com 

> Get-UrlRedirection -Enumerate http://microsoft.com/about 
http://microsoft.com/about 
https://microsoft.com/about 
https://www.microsoft.com/about 
https://www.microsoft.com/about/ 
https://www.microsoft.com/about/default.aspx 
https://www.microsoft.com/en-us/about/ 

Function Get-UrlRedirection { 
    [CmdletBinding()] 
    Param (
    [Parameter(Mandatory, ValueFromPipeline)] [Uri] $Url, 
    [switch] $Enumerate, 
    [int] $MaxRedirections = 50 # Use same default as [System.Net.HttpWebRequest] 
) 

    process { 
    try { 

     if ($Enumerate) { # Enumerate the whole redirection chain, from input URL to ultimate target, 
         # assuming the max. count of redirects is not exceeded. 
     # We must walk the chain of redirections one by one. 
     # If we disallow redirections, .GetResponse() fails and we must examine 
     # the exception's .Response object to get the redirect target. 
     $nextUrl = $Url 
     $urls = @($nextUrl.AbsoluteUri) # Start with the input Uri 
     $ultimateFound = $false 
     # Note: We add an extra loop iteration so we can determine whether 
     #  the ultimate target URL was reached or not. 
     foreach($i in 1..$($MaxRedirections+1)) { 
      Write-Verbose "Examining: $nextUrl" 
      $request = [System.Net.HttpWebRequest]::Create($nextUrl) 
      $request.AllowAutoRedirect = $False 
      try { 
      $response = $request.GetResponse() 
      # Note: In .NET *Core* the .GetResponse() for a redirected resource 
      #  with .AllowAutoRedirect -eq $False throws an *exception*. 
      #  We only get here on *Windows*, with the full .NET Framework. 
      #  We either have the ultimate target URL, or a redirection 
      #  whose target URL is reflected in .Headers['Location'] 
      #  !! Syntax `.Headers.Location` does NOT work. 
      $nextUrlStr = $response.Headers['Location'] 
      $response.Close() 
      # If the ultimate target URL was reached (it was already 
      # recorded in the previous iteration), and if so, simply exit the loop. 
      if (-not $nextUrlStr) { 
       $ultimateFound = $true 
       break 
      } 
      } catch [System.Net.WebException] { 
      # The presence of a 'Location' header implies that the 
      # exception must have been triggered by a HTTP redirection 
      # status code (3xx). 
      # $_.Exception.Response.StatusCode contains the specific code 
      # (as an enumeration value that can be case to [int]), if needed. 
      # !! Syntax `.Headers.Location` does NOT work. 
      $nextUrlStr = try { $_.Exception.Response.Headers['Location'] } catch {} 
      # Not being able to get a target URL implies that an unexpected 
      # error ocurred: re-throw it. 
      if (-not $nextUrlStr) { Throw } 
      } 
      Write-Verbose "Raw target: $nextUrlStr" 
      if ($nextUrlStr -match '^https?:') { # absolute URL 
      $nextUrl = $prevUrl = [Uri] $nextUrlStr 
      } else { # URL without scheme and server component 
      $nextUrl = $prevUrl = [Uri] ($prevUrl.Scheme + '://' + $prevUrl.Authority + $nextUrlStr) 
      } 
      if ($i -le $MaxRedirections) { $urls += $nextUrl.AbsoluteUri }   
     } 
     # Output the array of URLs (chain of redirections) as a *single* object. 
     Write-Output -NoEnumerate $urls 
     if (-not $ultimateFound) { Write-Warning "Enumeration of $Url redirections ended before reaching the ultimate target." } 

     } else { # Resolve just to the ultimate target, 
       # assuming the max. count of redirects is not exceeded. 

       # Note that .AllowAutoRedirect defaults to $True. 
     # This will fail, if there are more redirections than the specified 
     # or default maximum. 
     $request = [System.Net.HttpWebRequest]::Create($Url) 
     if ($PSBoundParameters.ContainsKey('MaxRedirections')) { 
      $request.MaximumAutomaticRedirections = $MaxRedirections 
     } 
     $response = $request.GetResponse() 
     # Output the ultimate target URL. 
     # If no redirection was involved, this is the same as the input URL. 
     $response.ResponseUri.AbsoluteUri 
     $response.Close() 

     } 

     } catch { 
     Write-Error $_ # Report the exception as a non-terminating error. 
    } 
    } # process 

} 

爲了專注於代碼,我省略了基於註釋的幫助以上;這裏是 - 簡單直接粘貼函數定義上面:

<# 
.SYNOPSIS 
Gets a URL's redirection target(s). 

.DESCRIPTION 
Given a URL, determines its redirection target(s), as indicated by responses 
with 3xx HTTP status codes. 

If the URL is not redirected, it is output as-is. 

By default, the ultimate target URL is determined (if there's a chain of 
redirections), but the number of redirections that are followed is limited 
to 50 by default, which you may change with -MaxRedirections. 

-Enumerate enumerates the redirection chain and returns an array of URLs. 

.PARAMETER Url 
The URL whose redirection target to determine. 
You may supply multiple URLs via the pipeline. 

.PARAMETER MaxRedirections 
Limits the number of redirections that are followed, 50 by default. 
If the limit is exceeded, a non-terminating error is reported. 

.PARAMETER Enumerate 
Enumerates the chain of redirections, if applicable, starting with 
the input URL itself, and outputs it as an array. 

If the number of actual redirections doesn't exceed the specified or default 
-MaxRedirections value, the entire chain up to the ultimate target URL is 
enumerated. 
Otherwise, a warning is issued to indicate that the ultimate target URL wasn't 
reached. 

All URLs are output in absolute form, even if the targets are defined as 
relative URLs. 

Note that, in order to support multiple input URLs via the pipeline, each 
array representing a redirection chain is output as a *single* object, so 
with multiple input URLs you'll get an array of arrays as output. 

.EXAMPLE 
> Get-UrlRedirection http://cnn.com 
http://www.cnn.com 

.EXAMPLE 
> Get-UrlRedirection -Enumerate http://microsoft.com/about 
http://microsoft.com/about 
https://microsoft.com/about 
https://www.microsoft.com/about 
https://www.microsoft.com/about/ 
https://www.microsoft.com/about/default.aspx 
https://www.microsoft.com/en-us/about/ 

.NOTES 
This function uses the [System.Net.HttpWebRequest] .NET class and was 
inspired by http://www.powershellmagazine.com/2013/01/29/pstip-retrieve-a-redirected-url/ 
#> 
1

如果您忽略拋出的錯誤,您將能夠檢查HTTP響應。新的URL將位於「位置」標題中。

嘗試下面的內容。

$url="https://jigsaw.w3.org/HTTP/300/301.html" 
$resp = Invoke-WebRequest -Method HEAD $url -MaximumRedirection 0 -ErrorAction Ignore 
$code = $resp.StatusCode 
Write-Host "URL: $url" 
Write-Host "ErrorCode: $code" 
if($code -eq 301) { 
    $loc = $resp.Headers.Location 
    Write-Host "New URL: $loc" 
} 
+0

嗯..這不會對PowerShell的工作6B5 AppImage上拱。 'resp.getType()''你不能在一個空值表達式上調用一個方法.'謝謝你試圖幫忙。除非有更好的結果,否則我會等待並標記爲答案。 – 0fnt

+1

在_Windows PowerShell_中運行良好,但PowerShell _Core_(在Windows和Unix上)的行爲已更改。[是否有意改變](https://github.com/PowerShell/PowerShell/issues/4534),我不知道。順便說一句:最好[避免'Write-Host'](http://www.jsnover.com/blog/2013/12/07/write-host-considered-harmful/)。 – mklement0

+1

另外值得注意的是,這隻會得到_immediate_重定向URL,它可能是或不可能是_ultimate_目標URL,因爲重定向可以被鏈接,這並不少見。此外,根據重定向的定義方式,結果可能是_relative_ URL。 – mklement0