You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Excel Add-in通过http及https对接Web服务的兼容登录问题咨询

需求背景

我正在修改一款通过Web服务接口从服务器读取数据的Excel Add-in,此前数据来源服务器不支持HTTPS协议,未来将逐步支持,但部分同用途服务器可能长期不会升级支持HTTPS。
因此我希望实现灵活的服务器登录逻辑:用户无需感知协议差异,仅需提供凭证和服务器名称即可登录,默认优先使用HTTPS协议,若目标服务器不支持则自动降级使用HTTP协议。

现有代码实现

身份验证服务封装类

public partial class AuthenticationService : System.Web.Services.Protocols.SoapHttpClientProtocol {
    
    public AuthenticationService() {
        this.Url = global::ExcelAddInExtension.Base.Properties.Settings.Default.ExcelAddInExtension_Base_ServiceReference_AuthenticationService;
        if ((this.IsLocalFileSystemWebService(this.Url) == true)) {
            this.UseDefaultCredentials = true;
            this.useDefaultCredentialsSetExplicitly = false;
        }
        else {
            this.useDefaultCredentialsSetExplicitly = true;
        }
    }

    public new string Url {
        get {
            return base.Url;
        }
        set {
            if ((((this.IsLocalFileSystemWebService(base.Url) == true) 
                        && (this.useDefaultCredentialsSetExplicitly == false)) 
                        && (this.IsLocalFileSystemWebService(value) == false))) {
                base.UseDefaultCredentials = false;
            }
            base.Url = value;
        }
    }

    [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://asp.net/ApplicationServices/v200/AuthenticationService/Login", RequestNamespace="http://asp.net/ApplicationServices/v200", ResponseNamespace="http://asp.net/ApplicationServices/v200", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
    public void Login([System.Xml.Serialization.XmlElementAttribute(IsNullable=true)] string username, [System.Xml.Serialization.XmlElementAttribute(IsNullable=true)] string password, [System.Xml.Serialization.XmlElementAttribute(IsNullable=true)] string customCredential, bool isPersistent, [System.Xml.Serialization.XmlIgnoreAttribute()] bool isPersistentSpecified, out bool LoginResult, [System.Xml.Serialization.XmlIgnoreAttribute()] out bool LoginResultSpecified) {
        object[] results = this.Invoke("Login", new object[] {
                    username,
                    password,
                    customCredential,
                    isPersistent,
                    isPersistentSpecified});
        LoginResult = ((bool)(results[0]));
        LoginResultSpecified = ((bool)(results[1]));
    }
}

初始登录调用逻辑

using (var authenticationService = new ServiceReference.AuthenticationService())
{
  authenticationService.Url = "https://server/AuthenticationService.svc";                        
  authenticationService.CookieContainer = new CookieContainer();
  bool loginResult;
  bool loginResultSpecified;

  try
    {
      authenticationService.Login(userName, password, "", true, true, out loginResult, out loginResultSpecified);
    }
    catch (Exception ex)
    {
       Debug.Write(string.Format("Authentication failed, Error message: {0}, \r\nerror inner exception \r\n{1}, \r\nerror stack trace \r\n{2}.", ex.Message, ex.InnerException, ex.StackTrace)));
       loginResult = false;
    }
}
问题描述

当尝试登录不支持HTTPS的服务器时,会收到预期报错:System.Net.Sockets.SocketException (0x80004005): No connection could be made because the target machine actively refused it server_ip_number:443。
最初的解决思路是在catch块中修改Url为HTTP协议重试:

authenticationService.Url = "http://server/AuthenticationService.svc";
authenticationService.Login(userName, password, "", true, true, out loginResult, out loginResultSpecified);

但误以为重试时仍返回相同的443端口拒绝连接报错,怀疑AuthenticationService对象在第一次请求后缓存了端口号。

最终解决方案

经排查,原问题是误将第一次HTTPS请求的报错日志当成了第二次HTTP重试的报错,SoapHttpClientProtocol本身不存在端口缓存机制,修改Url属性后重新发起请求会自动适配新的协议和对应端口,重试逻辑可正常生效。

修正后的完整登录逻辑如下:

using (var authenticationService = new ServiceReference.AuthenticationService())
{
    authenticationService.CookieContainer = new CookieContainer();
    bool loginResult;
    bool loginResultSpecified;
    string serverAddr = "server/AuthenticationService.svc"; // 实际场景从用户输入获取服务器地址

    // 优先尝试HTTPS
    authenticationService.Url = $"https://{serverAddr}";
    try
    {
        authenticationService.Login(userName, password, "", true, true, out loginResult, out loginResultSpecified);
    }
    catch (Exception ex)
    {
        // 仅当HTTPS连接相关异常时降级HTTP
        if (ex is SocketException || ex is System.Net.WebException { Status: System.Net.WebExceptionStatus.ConnectFailure or System.Net.WebExceptionStatus.SecureChannelFailure })
        {
            Debug.Write("HTTPS连接失败,降级使用HTTP重试");
            authenticationService.Url = $"http://{serverAddr}";
            try
            {
                authenticationService.Login(userName, password, "", true, true, out loginResult, out loginResultSpecified);
            }
            catch (Exception httpEx)
            {
                Debug.Write(string.Format("HTTP登录也失败,错误信息: {0}", httpEx.Message));
                loginResult = false;
            }
        }
        else
        {
            // 非连接类异常(如账号密码错误)直接返回失败,不重试
            Debug.Write(string.Format("登录失败,错误信息: {0}", ex.Message));
            loginResult = false;
        }
    }
}
优化建议
  • 可以将成功登录的协议类型缓存到本地配置,后续同域名请求直接使用对应协议,减少重复重试的开销
  • 对敏感场景可以增加HTTPS强制选项,符合安全要求的环境下关闭降级逻辑,避免HTTP传输带来的信息泄露风险

内容的提问来源于stack exchange,提问作者Markku Rintala

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 11:57:01