前天的範例,我們觀察到 Invoke-WebRequest -Uri SaveSession.aspx 時因伺服器端 Response.Redirect("ShowSession.aspx"), Invoke-WebRequest 會跳過 HTTP 302 重導過程直接傳回 ShowSession.aspx 的結果。這種無痕重導行為符合大部分的情境要求,但有些例外:若導向目的地非同網站其他頁面而是第三方站台,有時我們需要取得被導向網址以執行不同邏輯。

PowerShell 底層是用 HttpWebRequest 及 HttpWebResponse 實作,故可透過 HttpWebResponse.ResponseUri 取得最終 Response 的網址。以微軟網站為例,當瀏覽器連上 https://www.microsoft.com,會因語系設定被導向 http://www.microsoft.com/zh-tw,如以下範例程式:

$resp = (Invoke-WebRequest -Uri https://www.microsoft.com)
$resp.BaseResponse.ResponseUri.AbsoluteUri

順利得知被導向 http://www.microsoft.com/zh-tw:

以上是 PowerShell 4/5 的做法,PowerShell Core 改以 .NET Core 為基礎,Invoke-WebRequest 也順理成章改用 HttpClient,故寫法有所不同,BaseResponse.ResponseUri.AbsoluteUri 要改成 BaseResponse.RequestMessage.RequestUri.AbsoluteUri。

如果是 .NET 呢?

WebClient 底層也封裝了 HttpWebRequest,只留下 DownloadXXX()、UploadXXX() 等直接取得 string 或 byte[] 的簡單方式,無法存取 ResponseUri。除了回頭改用 HttpWebRequest (參考:如何使用 WebRequest/HttpWebRequest 存取網路資源 by Yowko),stackoverflow 上有網友分享透過繼承 WebClient 存取 protected GetWebResponse() 的巧妙解法,也很符合我的口味。

最後輪到 .NET Core / .NET 5。

借用剛才在 PowerShell Core 學到的 RequestMessage.RequestUri 知識,順利從 HttpClient 傳回結果取出被導向的目的地。

class Program
{
    static void Main(string[] args)
    {
        HttpClient hc = new HttpClient();
        var resp = hc.GetAsync("https://www.microsoft.com").Result;
        Console.Write("導向網址: ");
        Console.WriteLine(resp.RequestMessage.RequestUri);
        Console.WriteLine(resp.Content.ReadAsStringAsync().Result);
    }
}

【參考資料】

Getting Redirected URI’s in Powershell by Jeff Bolduan

Tips of how to get redirected URL with PowerShell/.NET Framework/.NET Core.


Comments

Be the first to post a comment

Post a comment