切换到 SSL 时 WebRequest returns 404

WebRequest returns 404 when switching to SSL

在 Xamarin 中使用 PCL 方法构建了一个应用程序并使用标准 HTTP 使其 100% 工作,我现在将远程测试服务器更改为使用带有自签名证书的 SSL。

该应用联系自定义 API 以登录服务器并查询特定数据。

我已经将应用更改为现在查看 SSL,最初收到有关身份验证无法正常工作或其他问题的错误,但关闭了 SSL 相关错误以进行测试:

ServicePointManager.ServerCertificateValidationCallback += (o, certificate, chain, errors) => true;

在我的 AppDelegate 文件中克服了那个错误的 FinishedLaunching 方法。

我现在在尝试登录 POST 给定的 URL 时收到 404/协议错误。

我正在为我的 RESTful 调用使用 HttpWebRequest,如果我改回纯 http,这会正常工作。

不知道为什么,但有些文章建议使用 ModernHttpClient,我也这样做了。我导入了组件(还使用 NuGet 添加了包)无济于事。

当联系 SSL 服务器时,我是否遗漏了我应该在与 httpwebresponse 相关的代码中配置的其他内容,或者这个组件是否根本无法与 SSL 服务器通信?

我的登录功能如下(无关代码removed/obfuscated):

public JsonUser postLogin(string csrfToken, string partnerId, string username, string password){
        string userEndPoint = SingletonAppSettngs.Instance ().apiEndPoint;
        userEndPoint = userEndPoint.Replace ("druid/", "");

        var request = WebRequest.CreateHttp(string.Format(this.apiBaseUrl + userEndPoint + @"user/login.json"));

        // Request header collection set up
        request.ContentType = "application/json";
        request.Headers.Add ("X-CSRF-Token", csrfToken);

        // Add other configs
        request.Method = "POST";

        using (var streamWriter = new StreamWriter(request.GetRequestStream()))
        {
            string json_body_content = "{\"username\":\"" + username + "\",\"password\":\"" + password + "\"}";

            streamWriter.Write(json_body_content);
            streamWriter.Flush();
            streamWriter.Close();
        }

        try{
            HttpWebResponse httpResponse = (HttpWebResponse)request.GetResponse();

            using (StreamReader reader = new StreamReader (httpResponse.GetResponseStream ())) {
                var content = reader.ReadToEnd ();
                content = content.Replace ("[],", "null,");
                content = content.Replace ("[]", "null");

                if (content == null) {
                    throw new Exception ("request_post_login - content is NULL");

                } else {
                    JsonSerializerSettings jss = new JsonSerializerSettings();
                    jss.NullValueHandling = NullValueHandling.Ignore;

                    JsonUser deserializedUser = JsonConvert.DeserializeObject<JsonUser>(content, jss);
                    if(content.Contains ("Hire company admin user")){
                        deserializedUser.user.roles.__invalid_name__5 = "Hire company admin user";
                        deserializedUser.user.roles.__invalid_name__2 = "authenticated user";
                    }

                    return deserializedUser;
                }
            }
        }catch(Exception httpEx){
            Console.WriteLine ("httpEx Exception: " + httpEx.Message);
            Console.WriteLine ("httpEx Inner Exception: " + httpEx.InnerException.Message);
            JsonUser JsonUserError = new JsonUser ();
            JsonUserError.ErrorMessage = "Error occured: " + httpEx.Message;
            return JsonUserError;
        }

    }

在使用 ModernHttpClient 发出 Web 请求时,我通常遵循以下模式。 Paul Betts 创建的另一个很棒的库是 refit,可用于简化 rest 调用。

    using (var client = new HttpClient(new NativeMessageHandler(false, false)))
    {
        client.BaseAddress = new Uri(BaseUrl, UriKind.Absolute);

        var result = await Refit.RestService.For<IRestApi>(client).GetData();

    }

如果使用自定义 SSLVerification,NativeMessageHandler 的第二个参数应设置为 true。

这里看看IRestApi

    public interface IRestApi
    {
        [Get("/foo/bar")]
        Task<Result> GetMovies();
    }

为了让它工作我必须做的事情的数量。

  1. 自签名证书必须允许 TLS 1.2
  2. 由于 API 基于 Drupal,必须在服务器上启用 HTTPS 并安装一个模块来管理 HTTP 特定页面。