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

如何在WCF的netHttpBinding中配置HTTPS?配置遇错求助

NetHttpBinding HTTPS(WSS)通信异常问题排查

问题描述

我正在开发一个基于NetHttpBinding的双工通信示例,HTTP模式下运行正常,但切换到HTTPS(WSS)时抛出以下异常:

System.ServiceModel.CommunicationException: 'An error occurred while making the HTTP request to https://localhost:8080/NetHttp. This could be due to the fact that the server certificate is not configured properly with HTTP.SYS in the HTTPS case. This could also be caused by a mismatch of the security binding between the client and the server.'

相关代码与配置

1. 服务契约(IHttpService.cs)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace NetHttpBindingPocSvc
{
    [ServiceContract(CallbackContract = typeof(IDuplexServiceCallBack))]
    public interface IHttpService
    {
        [OperationContract]
        void SendMessage(string message);
    }

    public interface IDuplexServiceCallBack
    {
        [OperationContract]
        void ReceiveMessage(string message);
    }
}

2. 服务实现类

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public class HttpService : IHttpService
{
    public void SendMessage(string message)
    {
        Console.WriteLine($"Message from client received: {message}");

        var callback = OperationContext.Current.GetCallbackChannel<IDuplexServiceCallBack>();
        if (callback != null)
        {
            callback.ReceiveMessage("Message has been received");
        }
    }
}

3. 服务托管代码

internal class Program
{
    static void Main(string[] args)
    {
        var serviceInstance = new ServiceHost(typeof(NetHttpBindingPocSvc.HttpService));
        serviceInstance.Open();
        Console.WriteLine($"Service is up and running");
        Console.ReadLine();
    }
}

4. 服务器端App.Config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
    </startup>
    <system.serviceModel>
        <protocolMapping>
            <add scheme="http" binding="netHttpBinding" />
            <add scheme="https" binding="netHttpsBinding" />
        </protocolMapping>
        <services>
            <service name="NetHttpBindingPocSvc.HttpService" behaviorConfiguration="netHttpBindingBehaviour">
                <endpoint address="" binding="netHttpBinding" contract="NetHttpBindingPocSvc.IHttpService" bindingConfiguration="netHttpBinding">
                </endpoint>
                <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
                <host>
                    <baseAddresses>
                        <add baseAddress="https://localhost:8080/NetHttp" />
                        <add baseAddress="http://localhost:8081/NetHttp"/>
                    </baseAddresses>
                </host>
            </service>
        </services>
        <bindings>
            <netHttpBinding>
                <binding name="netHttpBinding" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:40:00" sendTimeout="00:40:00"
                         transferMode="Buffered" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="20000000" maxBufferSize="2147483647"
                         maxReceivedMessageSize="2147483647">
                    <readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="20000000" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                    <reliableSession ordered="true" inactivityTimeout="00:40:00" enabled="false" />
                    <security mode="Transport">
                        <transport clientCredentialType="None"></transport>
                    </security>
                </binding>
            </netHttpBinding>
        </bindings>
        <behaviors>
            <serviceBehaviors>
                <behavior name="netHttpBindingBehaviour">
                    <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
                    <serviceDebug includeExceptionDetailInFaults="true" />
                    <serviceCredentials>
                        <serviceCertificate findValue="localhost" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
                    </serviceCredentials>
                </behavior>
            </serviceBehaviors>
        </behaviors>
    </system.serviceModel>
</configuration>

5. 客户端调用代码

internal class Program
{
    static void Main(string[] args)
    {
        var message = Console.ReadLine();
        string url = $"wss://localhost:8080/NetHttp";
        var instanceContext = new InstanceContext(new DuplexMessageReceiver());
        NetHttpService.HttpServiceClient client = new NetHttpService.HttpServiceClient(instanceContext);
        client.Endpoint.Address = new System.ServiceModel.EndpointAddress(new Uri(url), EndpointIdentity.CreateDnsIdentity("localhost"));
        //client.ClientCredentials.ClientCertificate.SetCertificate(System.Security.Cryptography.X509Certificates.StoreLocation.LocalMachine, System.Security.Cryptography.X509Certificates.StoreName.My, System.Security.Cryptography.X509Certificates.X509FindType.FindBySubjectName, "localhost");
        client.Open();
        client.SendMessage(message);
        Console.ReadLine();
    }
    public class DuplexMessageReceiver : NetHttpService.IHttpServiceCallback
    {
        public void ReceiveMessage(string message)
        {
            Console.WriteLine(message);
        }
    }
}

6. 客户端App.Config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
    </startup>
    <system.serviceModel>
        <bindings>
            <netHttpBinding>
                <binding name="NetHttpBinding_IHttpService">
                    <security mode="Transport">
                        <transport clientCredentialType="None" />
                    </security>
                    <webSocketSettings transportUsage="Always" />
                </binding>
            </netHttpBinding>
        </bindings>
        <client>
            <endpoint address="wss://localhost:8080/NetHttp" binding="netHttpBinding"
                bindingConfiguration="NetHttpBinding_IHttpService" contract="NetHttpService.IHttpService"
                name="NetHttpBinding_IHttpService" />
        </client>
    </system.serviceModel>
</configuration>

解决方案

1. 修正服务器端绑定与端点匹配问题

服务器端HTTPS地址对应的绑定应使用netHttpsBinding,而非netHttpBinding。修改服务器端App.Config:

  • 新增netHttpsBinding配置节点,复用原有绑定参数
  • 将HTTPS基础地址对应的端点绑定改为netHttpsBinding
  • 将mex端点改为mexHttpsBinding以支持HTTPS元数据获取

修改后的关键配置片段:

<services>
  <service name="NetHttpBindingPocSvc.HttpService" behaviorConfiguration="netHttpBindingBehaviour">
    <!-- HTTPS端点使用netHttpsBinding -->
    <endpoint address="" binding="netHttpsBinding" contract="NetHttpBindingPocSvc.IHttpService" bindingConfiguration="netHttpsBinding" />
    <!-- 保留HTTP端点使用netHttpBinding -->
    <endpoint address="http" binding="netHttpBinding" contract="NetHttpBindingPocSvc.IHttpService" bindingConfiguration="netHttpBinding" />
    <endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
    <host>
      <baseAddresses>
        <add baseAddress="https://localhost:8080/NetHttp" />
        <add baseAddress="http://localhost:8081/NetHttp"/>
      </baseAddresses>
    </host>
  </service>
</services>
<bindings>
  <netHttpsBinding>
    <binding name="netHttpsBinding" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:40:00" sendTimeout="00:40:00"
             transferMode="Buffered" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="20000000" maxBufferSize="2147483647"
             maxReceivedMessageSize="2147483647">
      <readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="20000000" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
      <reliableSession ordered="true" inactivityTimeout="00:40:00" enabled="false" />
      <security mode="Transport">
        <transport clientCredentialType="None"></transport>
      </security>
    </binding>
  </netHttpsBinding>
  <netHttpBinding>
    <binding name="netHttpBinding" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:40:00" sendTimeout="00:40:00"
             transferMode="Buffered" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="20000000" maxBufferSize="2147483647"
             maxReceivedMessageSize="2147483647">
      <readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="20000000" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
      <reliableSession ordered="true" inactivityTimeout="00:40:00" enabled="false" />
      <!-- HTTP模式下安全模式改为None -->
      <security mode="None">
        <transport clientCredentialType="None"></transport>
      </security>
    </binding>
  </netHttpBinding>
</bindings>

2. 绑定证书到HTTP.SYS端口

HTTPS需要将证书与端口绑定,以管理员身份运行命令提示符,执行以下命令:

netsh http add sslcert ipport=0.0.0.0:8080 certhash=你的证书指纹 appid={任意GUID}
  • 证书指纹可通过证书管理器获取:找到LocalMachine\My存储中的localhost证书,右键→属性→详细信息→指纹(去掉空格)
  • appid可生成一个新的GUID,例如{F5B74EB9-825E-4F6D-8AFE-5D35C6E12C68}

3. 客户端处理自签名证书信任问题

如果使用自签名证书,客户端默认会拒绝信任,需添加证书验证回调(仅测试环境使用):
在客户端Main方法开头添加:

// 跳过证书验证(测试环境用)
System.Net.ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;

4. 验证客户端配置匹配

确保客户端绑定的安全模式为Transport,地址为wss://localhost:8080/NetHttp,与服务器端配置一致。

核心原因

  • 服务器端点绑定类型与HTTPS协议不匹配:netHttpBinding对应HTTP,netHttpsBinding对应HTTPS
  • HTTPS证书未绑定到HTTP.SYS端口,导致SSL握手失败
  • 客户端未信任自签名证书,触发SSL验证错误

内容的提问来源于stack exchange,提问作者Akash Soni

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 17:49:57