WebUI3中的WebView2:如何禁用CORS以获取请求?

发布于 2025-01-30 11:15:56 字数 1441 浏览 4 评论 0 原文

我有一个简单的Web应用程序,我想在Winui应用程序中运行,该应用程序可以获取外部HTML内容:

    private async fetchHtml() {
        const url = document.querySelector<HTMLInputElement>("#txt-url")!.value;
        const html = await fetch(url).then(r => r.text());
        document.querySelector<HTMLTextAreaElement>("#txt-html")!.value = html;
    }

显然,这会遇到CORS错误。我想禁用它,但找不到winui3的任何方法:

  • this Answer 无济于事。

  • The URL is external URL so SetVirtualHostNameToFolderMapping suggested by

  • 我尝试注入自己的CORS标头,但它在 fetch 上不起作用( webresourceresponsereceived 事件仅在 fetch 请求上不触发事件):

c.WebResourceResponseReceived += (_, e) =>
{
    var origin = e.Request.Headers.FirstOrDefault(q => q.Key == "Origin").Value;
    if (!string.IsNullOrEmpty(origin))
    {
        e.Response.Headers.AppendHeader("Access-Control-Allow-Origin",
            new Uri(e.Request.Uri).GetLeftPart(UriPartial.Authority));
        e.Response.Headers.AppendHeader("Access-Control-Allow-Methods", "*");
        e.Response.Headers.AppendHeader("Access-Control-Allow-Headers", "*");
    }
};

I have a simple web app I would like to run in a WinUI app that can fetch external HTML content:

    private async fetchHtml() {
        const url = document.querySelector<HTMLInputElement>("#txt-url")!.value;
        const html = await fetch(url).then(r => r.text());
        document.querySelector<HTMLTextAreaElement>("#txt-html")!.value = html;
    }

Obviously this would hit a CORS error. I want to disable it but cannot find any way for WinUI3:

  • WebView2 in WinUI does not have EnsureCoreWebView2Async overload that takes CoreWebView2EnvironmentOptions so this answer does not help.

  • The URL is external URL so SetVirtualHostNameToFolderMapping suggested by this answer does not help as well.

  • I tried injecting my own CORS header but it does not work on fetch (WebResourceResponseReceived event is not fired only on fetch requests):

c.WebResourceResponseReceived += (_, e) =>
{
    var origin = e.Request.Headers.FirstOrDefault(q => q.Key == "Origin").Value;
    if (!string.IsNullOrEmpty(origin))
    {
        e.Response.Headers.AppendHeader("Access-Control-Allow-Origin",
            new Uri(e.Request.Uri).GetLeftPart(UriPartial.Authority));
        e.Response.Headers.AppendHeader("Access-Control-Allow-Methods", "*");
        e.Response.Headers.AppendHeader("Access-Control-Allow-Headers", "*");
    }
};

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

枕梦 2025-02-06 11:15:56

因此,事实证明,您实际上需要在 Webresourcerequested 事件中处理代理请求。 webresourceresponsereceived 在浏览器处理请求之后触发

要手动代理请求,您需要首先设置a Web资源请求的过滤器

// CoreWebView2WebResourceContext.XmlHttpRequest is triggered
// by fetches for some reason. This filter will listen for any URI.
this.webView.CoreWebView2.AddWebResourceRequestedFilter("*", CoreWebView2WebResourceContext.XmlHttpRequest);

然后,您可以像 webresourceresponsereceived 一样设置侦听器

this.webView.CoreWebView2.WebResourceRequested += this.CoreWebView2_WebResourceRequested;

,因此要代理请求,您需要设置 httpclient 并手动处理请求。

例如,这将代表所有请求,假设 httpclient 定义为 httpclient

private void CoreWebView2_WebResourceRequested(object sender, CoreWebView2WebResourceRequestedEventArgs e)
{
    HttpRequestMessage request = new(new HttpMethod(e.Request.Method), e.Request.Uri)
    {
        Content = new StreamContent(e.Request.Content)
    };

    foreach (KeyValuePair<string, string> header in e.Request.Headers)
    {
        // Copy base headers
        request.Headers.TryAddWithoutValidation(header.Key, header.Value);

        // Copy content headers
        request.Content.Headers.TryAddWithoutValidation(header.Key, header.Value);
    }

    // Make the request
    HttpResponseMessage response = httpClient.Send(request);

    // Custom headers
    response.Headers.Add("Access-Control-Allow-Origin", "*");

    // Webview2 Response expecting headers in a string with following format:
    //   key: value
    //   header2: value
    List<string> headers = response.Headers.Select(h => $"{h.Key}: {string.Join(",", h.Value)}").ToList();

    // Create Webview2 response
    CoreWebView2WebResourceResponse webView2WebResourceResponse = this.webView.CoreWebView2.Environment.CreateWebResourceResponse(
        response.Content.ReadAsStream(),
        (int)response.StatusCode,
        response.ReasonPhrase,
        string.Join('\n', headers));

    e.Response = webView2WebResourceResponse;
}

注意

在构建响应对象时,请勿使用 async 方法。 COM层不尊重线程。

So it turns out you actually need to handle proxying the request in the WebResourceRequested event. WebResourceResponseReceived is triggered after the browser handles the request.

To proxy the request manually, you need to first set up a web resource requested filter.

// CoreWebView2WebResourceContext.XmlHttpRequest is triggered
// by fetches for some reason. This filter will listen for any URI.
this.webView.CoreWebView2.AddWebResourceRequestedFilter("*", CoreWebView2WebResourceContext.XmlHttpRequest);

Then you can set up a listener just like for WebResourceResponseReceived

this.webView.CoreWebView2.WebResourceRequested += this.CoreWebView2_WebResourceRequested;

So to proxy the request, you need to set up an HttpClient and handle the requests manually.

For example, this will proxy all requests, assuming httpClient is defined as an HttpClient:

private void CoreWebView2_WebResourceRequested(object sender, CoreWebView2WebResourceRequestedEventArgs e)
{
    HttpRequestMessage request = new(new HttpMethod(e.Request.Method), e.Request.Uri)
    {
        Content = new StreamContent(e.Request.Content)
    };

    foreach (KeyValuePair<string, string> header in e.Request.Headers)
    {
        // Copy base headers
        request.Headers.TryAddWithoutValidation(header.Key, header.Value);

        // Copy content headers
        request.Content.Headers.TryAddWithoutValidation(header.Key, header.Value);
    }

    // Make the request
    HttpResponseMessage response = httpClient.Send(request);

    // Custom headers
    response.Headers.Add("Access-Control-Allow-Origin", "*");

    // Webview2 Response expecting headers in a string with following format:
    //   key: value
    //   header2: value
    List<string> headers = response.Headers.Select(h => 
quot;{h.Key}: {string.Join(",", h.Value)}").ToList();

    // Create Webview2 response
    CoreWebView2WebResourceResponse webView2WebResourceResponse = this.webView.CoreWebView2.Environment.CreateWebResourceResponse(
        response.Content.ReadAsStream(),
        (int)response.StatusCode,
        response.ReasonPhrase,
        string.Join('\n', headers));

    e.Response = webView2WebResourceResponse;
}

NOTE

Should not use async methods when building out a response object. The COM layer does not respect threading.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文