如何在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
相关产品推荐
相关产品推荐

