我正在使用C#和.NET 3.5。如您所知,我们可以在Web浏览器控件上向Navigate()添加自定义标头,如下所示:
var myUrl = "http://example.com/mypage.htm";
System.Uri uri = new Uri(myUrl);
byte[] authData = System.Text.UnicodeEncoding.UTF8.GetBytes("user:password");
string authHeader = "Authorization: Basic " + Convert.ToBase64String(authData) +"\r\n" +
"User-Agent: MyUserAgent\r\n";
webTDW8961nd.Navigate(uri, "", null, authHeader);
在上面的示例中,我们为单个导航设置了基本授权标头。现在来谈谈重定向。如果我们想要执行一个将重定向到另一个页面的javascript,则不会包含基本授权标题。
你的解决方案是什么?如何添加适用于所有请求的标头,而不仅仅是一次?
答案 0 :(得分:4)
问题在于虽然WinForm和WPF的WebBrowser
都只是围绕ActiveX IE控件的相对较薄的包装器,但它们并没有暴露我们感兴趣的所有事件(第二个提供的更少)比第一次)。有两种方法可以解决这个问题:首先,为WF浏览器控件创建子类并添加所需内容或使用WPF,然后在其中添加钩子。我发现第二种方法在WPF应用程序中更方便。
您只需要相关的界面。最简单的方法是添加对 Microsoft Internet Controls 的引用(您将在COM标题下找到这个VS)。这将打开一个名为SHDocVw
的命名空间,其中包含我们需要的所有内容(如果出于任何原因,您希望摆脱此依赖关系,则只需将P / Invoke接口复制到您自己的代码中)。
您可以使用反射获取基础浏览器。如果您过早地调用它,它将返回null
,因此我将其放入WebBrowser.Navigating
处理程序中:
using SHDocVw;
var ActiveXInstance = (IWebBrowser2)Browser.GetType().InvokeMember("ActiveXInstance", BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic, null, Browser, new object[] { });
只要你拥有它,你就可以使用浏览器做些好事。例如,您可以使用未直接公开的各种属性和方法:
ActiveXInstance.Silent = true; // suppresses script error dialogs
并添加缺少的事件挂钩:
var SetupEvents2 = (DWebBrowserEvents2_Event)ActiveXInstance;
SetupEvents2.BeforeNavigate2 += OnBeforeNavigate2;
有两个事件接口,2
变体包含较新的事件。您可以在MSDN.
然后,回到标题:BeforeNavigate2
事件允许您将额外的标题放入提供的对象中:
private void OnBeforeNavigate2(object pDisp, ref object URL, ref object Flags, ref object TargetFrameName, ref object PostData, ref object Headers, ref bool Cancel) {
Headers = $"Accept-Language: XX;en\r\n";
}
答案 1 :(得分:1)
要为每个请求添加自定义标头,您可以实现扩展方法:
public static class WebBrowserExtensions
{
public static void NavigateWithAuthorization(this WebBrowser browser, Uri uri)
{
byte[] authData = System.Text.Encoding.UTF8.GetBytes("user:password");
string authHeader = "Authorization: Basic " + Convert.ToBase64String(authData) + "\r\n" + "User-Agent: MyUserAgent\r\n";
browser.Navigate(uri, "", null, authHeader);
}
}
然后调用它而不是标准方法:
//browser.Navigate(uri, "", null, authHeader);
browser.NavigateWithAuthorization(uri);
第二个问题是关于重定向。但是你的场景不适用于简单的浏览器和小提琴手。这是Web协议的功能,当您重定向到另一个Uri时,您会使用新属性发起新请求。您可以用js代码撰写您的请求。
答案 2 :(得分:0)
在处理BeforeNavigate2
时,如果要包括其他标题,则需要取消当前的导航事件,还需要停止浏览器。然后,您需要再次导航到传递其他标题的URL。
这是我处理基本身份验证的方式,可以由guest
作为以下URL的用户名和密码进行测试:https://jigsaw.w3.org/HTTP/Basic/
string additionalHeaders;
private void Form1_Load(object sender, EventArgs e)
{
byte[] authData = System.Text.Encoding.UTF8.GetBytes("guest:guest");
additionalHeaders = $"Authorization: Basic {Convert.ToBase64String(authData)}\r\n";
webBrowser1.Navigate("about:blank", null, null, additionalHeaders);
var wbevents = (DWebBrowserEvents2_Event)webBrowser1.ActiveXInstance;
wbevents.BeforeNavigate2 += Wbevents_BeforeNavigate2;
webBrowser1.Navigate("https://jigsaw.w3.org/HTTP/Basic/", null, null, additionalHeaders);
}
private void Wbevents_BeforeNavigate2(object pDisp, ref object URL, ref object Flags,
ref object TargetFrameName, ref object PostData, ref object Headers, ref bool Cancel)
{
if (!$"{Headers}".Contains(additionalHeaders) &&
TargetFrameName == null &&
$"{URL}".ToLower().StartsWith("http"))
{
Cancel = true;
((IWebBrowser2)pDisp).Stop();
object headers = additionalHeaders + $"{Headers}";
object url = $"{URL}";
object flags = null;
object targetFrameName = $"{TargetFrameName}";
((IWebBrowser2)pDisp).Navigate2(ref url, ref flags,
ref targetFrameName, ref PostData, ref headers);
}
}
注意-导航不会在刷新时显示
浏览器中的功能/缺陷带有刷新。刷新浏览器时,不会引发Navigating
事件,这意味着刷新时不会添加标题。一种解决方法是禁用快捷方式和上下文菜单:
this.webBrowser1.WebBrowserShortcutsEnabled = false;
this.webBrowser1.IsWebBrowserContextMenuEnabled = false;