Raymond Chen 2024年2月12日
如何让 Windows 运行时 HttpClient 显示基本认证提示?
一位客户尝试在使用传统的 Win32 应用程序时,让 Windows 运行时的 Windows.Web.Http.HttpClient
显示基本认证提示。不幸的是,即使他们设置了 AllowUI = true
,也没有出现认证对话框;请求报告的状态是 401(未授权)。
namespace winrt
{
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Web::Http;
using namespace winrt::Windows::Web::Http::Filters;
}
winrt::IAsyncOperation<winrt::HttpStatusCode> Sample(HWND hwnd)
{
auto uri = winrt::Uri(L"http://httpbin.org/basic-auth/user/password");
auto filter = winrt::HttpBaseProtocolFilter();
filter.AllowUI(true);
auto client = winrt::HttpClient(filter);
auto result = co_await client.GetAsync(uri);
co_return result.StatusCode();
}
最初,Windows 运行时命名空间中的对象是为 UWP 应用(通用 Windows 平台)设计的。在 UWP 应用中,每个线程最多可以有一个 CoreWindow 对象,Windows 运行时对象通常通过询问线程其 CoreWindow 来推断它们的 UI 上下文,然后使用该 CoreWindow 进行任何进一步的用户界面操作。
但是,传统的 Win32 应用程序并不遵循“每个线程一个 CoreWindow”的模型。它们可以在每个线程上创建多个窗口,而且这些窗口都不是必需的 CoreWindow。在这些条件下,为 UWP 应用设计的 Windows 运行时对象遇到了问题:它们应该使用哪个窗口来进行用户界面操作?
在传统 Win32 应用程序中使用时,HttpBaseProtocolFilter
尝试猜测要使用哪个窗口:有时它猜对了,有时猜错了,有时猜测结果是空的。
为了避免猜测,使用 IInitializeWithWindow
接口(我们之前讨论过)给 HttpBaseProtocolFilter
一个明确的窗口来使用。
namespace winrt
{
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Web::Http;
using namespace winrt::Windows::Web::Http::Filters;
}
winrt::IAsyncOperation<winrt::HttpStatusCode> Sample(HWND hwnd)
{
auto uri = winrt::Uri(L"http://httpbin.org/basic-auth/user/password");
auto filter = winrt::HttpBaseProtocolFilter();
filter.as<IInitializeWithWindow>()->Initialize(hwnd);
filter.AllowUI(true);
auto client = winrt::HttpClient(filter);
auto result = co_await client.GetAsync(uri);
co_return result.StatusCode();
}
有了这个额外的提示,HttpBaseProtocolFilter
将能够显示基本认证对话框。
这种模型甚至在引入 AppWindow 对象后,对 UWP 应用也停止了工作,AppWindow 对象允许你在单个线程上创建多个窗口。