网络请求的自定义管理

Microsoft Edge WebView2 控件允许你与网络请求交互和修改网络请求。 可以使用 和 WebResourceResponseReceived 事件提供响应或修改网络请求WebResourceRequested。 还有一个特殊功能,允许你使用 NavigateWithWebResourceRequest API导航特定的网络请求。

本文介绍如何修改网络请求。 使用此 API 和方法可以:

  • 将本地文件内容上传到应用,以添加对脱机功能的支持。
  • 阻止网页中的内容,例如特定图像。
  • 微调特定页面的身份验证。

术语:

Term 定义
拦截 主机应用可以截获从 WebView2 控件发送到 HTTP 服务器的请求、读取或修改请求,然后将未更改或修改的请求发送到 HTTP 服务器 (或本地代码,而不是 HTTP 服务器) 。
覆盖 主机应用可以重写从 HTTP 服务器发送到 WebView2 控件的响应,并将自定义响应发送到 WebView2 控件,而不是原始响应。

何时使用自定义方法与基本方法

WebResourceRequested 事件是一个低级别 API,可提供更多控制,但需要更多编码,并且使用起来很复杂。 对于某些常见方案,我们提供更易于使用且针对这些特定方案进行了优化的 API,建议使用这些 API,而不是本文中讨论的 API。

最好在可行时使用以下其他方法,而不是使用 WebResourceRequested API:

注意: 对于具有虚拟主机名的 URL,不支持使用 WebResourceRequested 事件。 这是因为 WebResourceRequested 不会为 SetVirtualHostNameToFolderMapping 方法触发事件。

主机应用、WebView2 控件和 HTTP 服务器的交互方式

WebView2 控件位于主机应用和 HTTP 服务器之间。 当主机应用导航到 URI 时,WebView2 控件会向 HTTP 服务器发送请求。 然后,HTTP 服务器将响应发送到 WebView2 控件。

截获请求,以监视或修改请求

主机应用可以 截获 从 WebView2 控件发送到 HTTP 服务器的请求、读取或修改请求,然后将未更改或修改的请求发送到 HTTP 服务器 (或本地代码,而不是 HTTP 服务器) 。

通过截获请求,可以自定义标头内容、URL 或 GET/POST 方法。 主机应用可能需要截获请求,以在请求中提供可选 POST 内容。

主机应用可以使用以下 API 更改请求的属性:

标头可以执行的操作

HTTP 标头提供有关请求或响应的重要信息和元数据。 通过更改 标头 ,可以在网络上执行强大的操作。

请求标头可用于指示响应 (的格式,例如Accept-*) 标头、设置身份验证令牌、读取和写入 cookie (敏感信息) 、修改用户代理等。 响应标头可用于提供更多响应上下文。

根据 URL 和资源类型筛选 WebResourceRequested 事件

若要接收 WebResourceRequested 事件,请根据 URL 和资源类型为主机应用感兴趣的请求指定筛选器。

例如,假设主机应用正在尝试替换图像。 在这种情况下,主机应用仅对图像的事件感兴趣 WebResourceRequested 。 主机应用仅通过指定 resourceContext 图像的筛选器来获取图像的事件。

另一个示例是,如果主机应用只对站点下的所有请求感兴趣,例如 https://example.com。 然后,应用可以将 URL 筛选器指定为 https://example.com/* 来获取与该网站关联的事件。

有关 URL 筛选器工作原理的详细信息,请参阅 CoreWebView2.AddWebResourceRequestedFilter 方法 > 备注

为何要截获从 WebView2 发送的请求?

通过拦截从 WebView2 发送的请求,可以进一步配置请求。 主机应用可能希望提供可选内容,作为 WebView2 控件自己不知道的请求的一部分。 某些方案包括:

  • 你正在登录到页面,并且应用具有凭据,因此应用可以提供身份验证标头,而无需用户输入这些凭据。
  • 你需要应用中的脱机功能,以便在未检测到 Internet 连接时将 URL 重定向到本地文件路径。
  • 你想要通过 POST 请求将本地文件内容上传到请求服务器。

修改请求的顺序

修改请求的顺序关系图

  1. 主机应用设置 WebResourceRequested 筛选器。
  2. 主机应用定义 和 WebResourceResponseReceivedWebResourceRequested事件处理程序。
  3. 主机应用将 WebView2 控件导航到网页。
  4. WebView2 控件为网页所需的资源创建请求。
  5. WebView2 控件将 WebResourceRequested 事件触发到主机应用。
  6. 主机应用侦听并处理 WebResourceRequested 事件。
  7. 此时,主机应用可以修改标头。 主机应用还可以延迟 WebResourceRequested 事件,这意味着主机应用会要求更多时间来决定要执行的操作。
  8. WebView2 网络堆栈可以添加更多标头 (例如,可以) 添加 Cookie 和授权标头。
  9. WebView2 控件将请求发送到 HTTP 服务器。
  10. HTTP 服务器将响应发送到 WebView2 控件。
  11. WebView2 控件触发事件 WebResourceResponseReceived
  12. 主机应用侦听 WebResourceResponseReceived 并处理事件。

示例:截获请求,以监视或修改请求

在以下示例中,主机应用 截获 从 WebView2 控件发送到 http://www.example.com HTTP 服务器的文档请求,添加自定义标头值并发送请求。

// Add a filter to select all resource types under http://www.example.com
webView.CoreWebView2.AddWebResourceRequestedFilter(
      "http://www.example.com/*", CoreWebView2WebResourceContext.All);
webView.CoreWebView2.WebResourceRequested += delegate (
   object sender, CoreWebView2WebResourceRequestedEventArgs args) {
   CoreWebView2WebResourceContext resourceContext = args.ResourceContext;
   // Only intercept the document resources
   if (resourceContext != CoreWebView2WebResourceContext.Document)
   {
      return;
   }
   CoreWebView2HttpRequestHeaders requestHeaders = args.Request.Headers;
   requestHeaders.SetHeader("Custom", "Value");
};

重写响应,以主动替换它

默认情况下,HTTP 服务器将响应发送到 WebView2 控件。 主机应用可以 重写 从 HTTP 服务器发送到 WebView2 控件的响应,并将自定义响应发送到 WebView2 控件,而不是原始响应。

重写响应的顺序

重写响应的序列图

  1. 主机应用设置 WebResourceRequested 筛选器。
  2. 主机应用定义 和 WebResourceResponseReceivedWebResourceRequested事件处理程序。
  3. 主机应用将 WebView2 控件导航到网页。
  4. WebView2 控件为网页所需的资源创建请求。
  5. WebView2 控件将 WebResourceRequested 事件触发到主机应用。
  6. 主机应用侦听并处理 WebResourceRequested 事件。
  7. 主机应用设置对事件处理程序的 WebResourceRequested 响应。 主机应用还可以延迟 WebResourceRequested 事件,这意味着主机应用会要求更多时间来决定要执行的操作。
  8. WebView2 控件将响应呈现为资源。

示例:重写响应,以主动替换它

// Add a filter to select all image resources
webView.CoreWebView2.AddWebResourceRequestedFilter(
      "*", CoreWebView2WebResourceContext.Image);
webView.CoreWebView2.WebResourceRequested += delegate (
   object sender, CoreWebView2WebResourceRequestedEventArgs args) {
    
   // Replace the remote image resource with a local one specified at the path customImagePath.
   // If response is not set, the request will continue as it is.
   FileStream fs = File.Open(customImagePath, FileMode.Open);
   CoreWebView2WebResourceResponse response = webView.CoreWebView2.Environment.CreateWebResourceResponse(fs, 200, "OK", "Content-Type: image/jpeg");
   args.Response = response;
};

构造自定义请求并使用该请求进行导航

方法 NavigateWithWebResourceRequest 允许主机应用使用自定义 WebResourceRequest导航 WebView2 控件。 可以使用此 API 创建具有自定义标头和内容的 GET 或 POST 请求。 然后,WebView2 控件将使用此自定义请求进行导航。

示例:构造自定义请求并使用该请求进行导航

// This code posts text input=Hello to the POST form page in W3Schools.

// Need to convert post data to UTF-8 as required by the application/x-www-form-urlencoded Content-Type 
UTF8Encoding utfEncoding = new UTF8Encoding();
byte[] postData = utfEncoding.GetBytes("input=Hello");

MemoryStream postDataStream = new MemoryStream(postData.Length);
postDataStream.Write(postData, 0, postData.Length);
postDataStream.Seek(0, SeekOrigin.Begin);

// This acts as a HTML form submit to https://www.w3schools.com/action_page.php
CoreWebView2WebResourceRequest webResourceRequest = 
environment.CreateWebResourceRequest("https://www.w3schools.com/action_page.php",
                                     "POST",
                                     postDataStream,
                                    "Content-Type: application/x-www-form-urlencoded");
webView.CoreWebView2.NavigateWithWebResourceRequest(webResourceRequest);

通过 WebResourceResponseReceived 事件监视请求和响应

可以通过 事件监视请求和响应 WebResourceResponseReceived ,以读取任何标头值。

示例:通过 WebResourceResponseReceived 事件监视请求和响应

此示例演示如何通过 事件监视请求和响应 WebResourceResponseReceived 来读取授权标头值。

以下代码演示了如何使用 WebResourceResponseReceived 事件。

WebView.CoreWebView2.WebResourceResponseReceived += CoreWebView2_WebResourceResponseReceived;

// Note: modifications made to request are set but have no effect on WebView processing it.
private async void WebView_WebResourceResponseReceived(object sender, CoreWebView2WebResourceResponseReceivedEventArgs e)
{
    // Actual headers sent with request
    foreach (var current in e.Request.Headers)
    {
        Console.WriteLine(current);
    }

    // Headers in response received
    foreach (var current in e.Response.Headers)
    {
        Console.WriteLine(current);
    }

    // Status code from response received
    int status = e.Response.StatusCode;
    if (status == 200)
    {
        Console.WriteLine("Request succeeded!");

        // Get response body
        try
        {
            System.IO.Stream content = await e.Response.GetContentAsync();
            // Null will be returned if no content was found for the response.
            if (content != null)
            {
                DoSomethingWithResponseContent(content);
            }
        }
        catch (COMException ex)
        {
            // A COMException will be thrown if the content failed to load.
        }
    }
}

API 参考概述

请求:

响应:

另请参阅