WebView - Define User-Agent on every request

2019-06-17 17:52发布

问题:

Currently, I am setting the User-Agent of a request message as follows:

var rm = new HttpRequestMessage(HttpMethod.Post, new Uri("http://example.com"));       
rm.Headers.Add("User-Agent", "UserAgentString");
webView.NavigateWithHttpRequestMessage(rm);

Everything works as expected.

But, when I am navigating to an another page, by clicking a link on the site for example, the User-Agent resets to the default of the WebView.

Is there any way of setting the User-Agent permanently or changing it on every request made?

Thanks, George

回答1:

The only way I've been able to get this to work fairly reliably is by using the NavigationStarting Event to cancel the page load and get the current url, then use a custom event to trigger the new page load with the correct UA.

public sealed partial class MainPage : Page
{
    private bool headerSent;
    private Uri uri;

    private delegate void NavigateHandler(object sender, EventArgs e);
    private event NavigateHandler OnNavigate;

    public MainPage()
    {
        this.InitializeComponent();

        this.OnNavigate += new NavigateHandler(Navigate);
        this.headerSent = false;
        this.webview.Navigate(new Uri("https://netflix.com"));
    }

    private void Navigate(object sender, EventArgs e)
    {
        this.headerSent = true;
        var rm = new HttpRequestMessage(HttpMethod.Post, this.uri);

        rm.Headers.Add("User-Agent", @"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10136");
        this.webview.NavigateWithHttpRequestMessage(rm);
    }

    private void webview_NavigationStarting(WebView sender, WebViewNavigationStartingEventArgs args)
    {
        if (!headerSent)
        {
            args.Cancel = true;
            this.uri = args.Uri;
            OnNavigate(this, new EventArgs());
        }
        else if (headerSent)
        {
            headerSent = false;
        }
    }
}

Not pretty, but it seems to work.



回答2:

NavigationStarting occurs before the webview navigates to new content. You can cancel that operation get the args.Uri and navigate with HttpRequestMessage. There is also FrameNavigationStarting.

WebView wb = new WebView();
wb.NavigationStarting += A_NavigationStarting;

private void A_NavigationStarting(WebView sender, WebViewNavigationStartingEventArgs args)
{
    //this will throw `StackOverflowException` so you have to add a condition here
    if(handled)
    {
        args.Cancel = true;
        var rm = new HttpRequestMessage(HttpMethod.Post, args.Uri);

        rm.Headers.Add("User-Agent", "UserAgentString");
        sender.NavigateWithHttpRequestMessage(rm);
    }
}


回答3:

I found this trick by Matt Dot. This will permanently change the user-agent string. Any WebView request, whether manual or through a link-click inside the HTML, will have your value sent as the User-Agent header.

Here's the source in case the link dies.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace UA
{
    public static class UserAgent
    {
        const int URLMON_OPTION_USERAGENT = 0x10000001;

        [DllImport("urlmon.dll", CharSet = CharSet.Ansi)]
        private static extern int UrlMkSetSessionOption(int dwOption, string pBuffer, int dwBufferLength, int dwReserved);

        [DllImport("urlmon.dll", CharSet = CharSet.Ansi)]
        private static extern int UrlMkGetSessionOption(int dwOption, StringBuilder pBuffer, int dwBufferLength, ref int pdwBufferLength, int dwReserved);

        public static string GetUserAgent()
        {
            int capacity = 255;
            var buf = new StringBuilder(capacity);
            int length = 0;

            UrlMkGetSessionOption(URLMON_OPTION_USERAGENT, buf, capacity, ref length, 0);

            return buf.ToString();
        }

        public static void SetUserAgent(string agent)
        {
            var hr = UrlMkSetSessionOption(URLMON_OPTION_USERAGENT, agent, agent.Length, 0);
            var ex = Marshal.GetExceptionForHR(hr);
            if(null != ex)
            {
                throw ex;
            }
        }

        public static void AppendUserAgent(string suffix)
        {
            SetUserAgent(GetUserAgent() + suffix);
        }
    }
}

You can change this value anywhere in your app, but if you want it permanently set, use the App.xaml.cs constructor:

public App()
{
    UA.UserAgent.SetUserAgent("Firefox ;)");

    // ...
}