Xamarin.forms 将授权标头添加到Xamarin表单Android WebView中的所有请求

Xamarin.forms 将授权标头添加到Xamarin表单Android WebView中的所有请求,xamarin.forms,android-webview,Xamarin.forms,Android Webview,我正在尝试向webview客户端添加自定义http头(用于授权)。 它似乎在某些情况下工作,我可以登录到一个网页,而无需输入用户名和密码,我会被重定向到另一个页面。但是,当页面调用其他资源以获取填充有数据的元素时,会抛出一个错误,并调用OnReceiveDhttPeror。我得到的错误是401 unauthorized,当我查看IWebResourceRequest上的标题时,我根本看不到授权标题。 是我遗漏了什么,还是有人有同样的问题 使用Xamarin Forms 2.3.3.180和目标A

我正在尝试向webview客户端添加自定义http头(用于授权)。 它似乎在某些情况下工作,我可以登录到一个网页,而无需输入用户名和密码,我会被重定向到另一个页面。但是,当页面调用其他资源以获取填充有数据的元素时,会抛出一个错误,并调用OnReceiveDhttPeror。我得到的错误是401 unauthorized,当我查看IWebResourceRequest上的标题时,我根本看不到授权标题。 是我遗漏了什么,还是有人有同样的问题

使用Xamarin Forms 2.3.3.180和目标API 21(Android 5.0棒棒糖),使用Android 7.1牛轧糖编译

我在《邮递员》中尝试过向请求添加标题,效果非常好

渲染器:

public class MyWebViewRenderer : WebViewRenderer
{
    private MyWebViewClient _webViewClient;

    protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
    {
        base.OnElementChanged(e);

        if(_webViewClient == null)
            _webViewClient = new MyWebViewClient();

        Control.SetWebViewClient(_webViewClient);
        Control.LongClickable = false;
        Control.HapticFeedbackEnabled = false;
        Control.Settings.JavaScriptEnabled = true;

        var data = Encoding.GetEncoding("ISO-8859-1").GetBytes("username:password");
        var base64string = Base64.EncodeToString(data, Base64Flags.NoWrap);

        var headers = new Dictionary<string, string>();
        headers.Add("Authorization", $"Basic {base64string}")

        Control.LoadUrl(Control.Url, headers);
    }
}
public override bool ShouldOverrideUrlLoading(WebView view, string url)
{
    WebView.SetWebContentsDebuggingEnabled(true);

    var data = Encoding.GetEncoding("ISO-8859-1").GetBytes("username:password");
    var base64string = Base64.EncodeToString(data, Base64Flags.NoWrap);

    var headers = new Dictionary<string, string>();
    headers.Add("Authorization", $"Basic {base64string}")

    view.LoadUrl(url, headers);
    return true;
}

public override WebResourceResponse ShouldInterceptRequest(WebView view, IWebResourceRequest urlResource)
{
    //headers does not always contains authorization header, so let's add it.
    if (!urlResource.RequestHeaders.ContainsKey("authorization") && !urlResource.RequestHeaders.ContainsKey("Authorization"))
    {
       var data = Encoding.GetEncoding("ISO-8859-1").GetBytes("username:password");
       var base64string = Base64.EncodeToString(data, Base64Flags.NoWrap);

       urlResource.RequestHeaders.Add("Authorization", $"{base64string}");
     }

        return base.ShouldInterceptRequest(view, urlResource);
}

public override void OnReceivedHttpError(WebView view, IWebResourceRequest request, WebResourceResponse errorResponse)
{
    base.OnReceivedHttpError(view, request, errorResponse);
}
公共类MyWebViewRenderer:WebViewRenderer
{
私有MyWebViewClient webViewClient;
受保护的覆盖无效OnElementChanged(ElementChangedEventArgs e)
{
基础。一个要素发生变化(e);
如果(_webViewClient==null)
_webViewClient=新的MyWebViewClient();
控件。SetWebViewClient(_webViewClient);
Control.LongClickable=false;
Control.HapticFeedbackEnabled=错误;
Control.Settings.JavaScriptEnabled=true;
var data=Encoding.GetEncoding(“ISO-8859-1”).GetBytes(“用户名:密码”);
var base64string=Base64.EncodeToString(数据,Base64Flags.NoWrap);
var headers=newdictionary();
headers.Add(“Authorization”,$“Basic{base64string}”)
Control.LoadUrl(Control.Url,标题);
}
}
WebViewClient:

public class MyWebViewRenderer : WebViewRenderer
{
    private MyWebViewClient _webViewClient;

    protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
    {
        base.OnElementChanged(e);

        if(_webViewClient == null)
            _webViewClient = new MyWebViewClient();

        Control.SetWebViewClient(_webViewClient);
        Control.LongClickable = false;
        Control.HapticFeedbackEnabled = false;
        Control.Settings.JavaScriptEnabled = true;

        var data = Encoding.GetEncoding("ISO-8859-1").GetBytes("username:password");
        var base64string = Base64.EncodeToString(data, Base64Flags.NoWrap);

        var headers = new Dictionary<string, string>();
        headers.Add("Authorization", $"Basic {base64string}")

        Control.LoadUrl(Control.Url, headers);
    }
}
public override bool ShouldOverrideUrlLoading(WebView view, string url)
{
    WebView.SetWebContentsDebuggingEnabled(true);

    var data = Encoding.GetEncoding("ISO-8859-1").GetBytes("username:password");
    var base64string = Base64.EncodeToString(data, Base64Flags.NoWrap);

    var headers = new Dictionary<string, string>();
    headers.Add("Authorization", $"Basic {base64string}")

    view.LoadUrl(url, headers);
    return true;
}

public override WebResourceResponse ShouldInterceptRequest(WebView view, IWebResourceRequest urlResource)
{
    //headers does not always contains authorization header, so let's add it.
    if (!urlResource.RequestHeaders.ContainsKey("authorization") && !urlResource.RequestHeaders.ContainsKey("Authorization"))
    {
       var data = Encoding.GetEncoding("ISO-8859-1").GetBytes("username:password");
       var base64string = Base64.EncodeToString(data, Base64Flags.NoWrap);

       urlResource.RequestHeaders.Add("Authorization", $"{base64string}");
     }

        return base.ShouldInterceptRequest(view, urlResource);
}

public override void OnReceivedHttpError(WebView view, IWebResourceRequest request, WebResourceResponse errorResponse)
{
    base.OnReceivedHttpError(view, request, errorResponse);
}
public override bool ShouldOverrideUrlLoading(WebView视图,字符串url)
{
WebView.SetWebContentsDebuggingEnabled(true);
var data=Encoding.GetEncoding(“ISO-8859-1”).GetBytes(“用户名:密码”);
var base64string=Base64.EncodeToString(数据,Base64Flags.NoWrap);
var headers=newdictionary();
headers.Add(“Authorization”,$“Basic{base64string}”)
LoadUrl(url、标题);
返回true;
}
公共覆盖WebResourceResponse ShouldInterceptRequest(WebView视图,iWebResourceRequestUrlResource)
{
//标头并不总是包含授权标头,所以让我们添加它。
如果(!urlResource.RequestHeaders.ContainsKey(“授权”)和&!urlResource.RequestHeaders.ContainsKey(“授权”))
{
var data=Encoding.GetEncoding(“ISO-8859-1”).GetBytes(“用户名:密码”);
var base64string=Base64.EncodeToString(数据,Base64Flags.NoWrap);
添加(“授权”、$“{base64string}”);
}
返回base.ShouldInterceptRequest(视图,urlResource);
}
public override void onReceivedHttPeror(WebView视图、IWebResourceRequest请求、WebResourceResponse errorResponse)
{
base.onReceivedHttPeror(查看、请求、错误响应);
}

如果您只需要get请求上的标题,下面的代码就可以了。然而,POST请求是另一个问题。我需要做一件类似的事情(针对所有请求,而不仅仅是GET),我所能说的是没有直接的解决方案,至少我没有找到一个(除了编写自己的网络驱动程序之外,我已经尝试了所有方法)。我尝试过很多方法(ShouldOverrideUrlLoading、ShouldInterceptRequest、CustomLoadUrl和PostUrl等),但没有一种方法能提供100%的解决方案。关于这一点有很多错误的信息,所以我认为需要澄清一下,因为我花了两天的时间都没有成功

以下是我学到的:


如果您只需要GET请求中的头,那就很简单了。只需创建一个
WebViewClient
的实现,并覆盖
ShouldOverrideUrlLoading
,如下所示:

[assembly: ExportRenderer(typeof(Xamarin.Forms.WebView), typeof(App.Android.HybridWebViewRenderer))]
namespace App.Android
{
    public class HybridWebViewRenderer : WebViewRenderer
    {

        public HybridWebViewRenderer(Context context) : base(context)
        {
        }

        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
        {
            base.OnElementChanged(e);
            Control.SetWebViewClient(new CustomWebViewClient());
        }
    }
    public class CustomWebViewClient : WebViewClient
    {
        public override bool ShouldOverrideUrlLoading(Android.Webkit.WebView view, string url)
        {
            Dictionary<string, string> headers = new Dictionary<string, string>
            {
                ["Name"] = "value"
            };
            view.LoadUrl(url, headers);
            return true;
        }
    }
}
[程序集:ExportRenderer(typeof(Xamarin.Forms.WebView)、typeof(App.Android.HybridWebViewRenderer))]
名称空间App.Android
{
公共类HybridWebViewRenderer:WebViewRenderer
{
公共HybridWebViewRenderer(上下文):基础(上下文)
{
}
受保护的覆盖无效OnElementChanged(ElementChangedEventArgs e)
{
基础。一个要素发生变化(e);
Control.SetWebViewClient(新的CustomWebViewClient());
}
}
公共类CustomWebViewClient:WebViewClient
{
公共覆盖bool ShouldOverrideUrlLoading(Android.Webkit.WebView视图,字符串url)
{
字典头=新字典
{
[“名称”]=“值”
};
LoadUrl(url、标题);
返回true;
}
}
}
但是,如果您需要在其他请求(特别是POST请求)中使用头,那么实际上并没有一个完美的解决方案。许多答案都告诉您要覆盖
ShouldInterceptRequest
,但这不太可能有帮助
ShouldInterceptRequest
提供一个
IWebResourceRequest
,其中包含请求的URL、方法(即POST)和标题。有一些答案表明,通过执行
request.headers.Add(“Name”、“Value”)
添加标题是可行的解决方案,但这是错误的。
IWebResourceRequest
未被
WebView
的内部逻辑使用,因此修改它是无用的

您可以在
ShouldInterceptRequest
中编写自己的HTTP客户机,其中包括您自己的头,以执行请求并返回
WebResourceResponse
对象。同样,这适用于GET请求,但问题是,即使我们可以拦截POST请求,我们也无法确定请求中的内容,因为请求内容不包括在
IWebResourceRequest
对象中。因此,我们无法准确地手动执行请求。所以,除非POST请求的内容不重要或者可以以某种方式