为啥要用Winfrom发布https的web服务呢?就得说的不守信用的w3c协议了。原来谷歌浏览器支持https调用ws,在90版本之后直接禁止所有https访问非https资源了。不得不说垄断任性啊。
为了解决新版浏览器在https时候无法驱动cs程序的问题,再引入一个调用通道,就是winform发布https。
首先用linux得到证书
# 生成私钥
openssl genrsa -aes256 -passout "pass:mypassword" -out key.pem 4096
# 生成公钥
openssl req -new -x509 -days 3650 -key key.pem -passin "pass:mypassword" -out cert.csr -subj "/C=CN/ST=BeiJing/L=BeiJing/O=Gongshi/OU=Group/CN=www.baidu.com//emailAddress=zzzz@qq.com.cn"
# 打包为pfx
openssl pkcs12 -export -in cert.csr -inkey key.pem -out dotnet.linux.pfx
这样就得到了.pfx的证书文件给winform程序使用
winform代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.IO;
using System.Diagnostics;
namespace Http
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
LISHttpsServer service = new LISHttpsServer();
service.InitServer("8080");
}
}
}
包装的服务类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.IO;
using System.Diagnostics;
namespace Http
{
/// <summary>
/// 处理请求消息
/// </summary>
/// <param name="msg">消息</param>
/// <param name="request">请求对象</param>
/// <param name="response">回复对象</param>
public delegate void DealRequestMsg(string msg,HttpListenerRequest request, HttpListenerResponse response);
/// <summary>
/// http监听对象
/// </summary>
public class ZLZHttpsServer
{
/// <summary>
/// 监听对象
/// </summary>
HttpListener httpobj = null;
/// <summary>
/// 处理消息回调
/// </summary>
DealRequestMsg DealMasg = null;
/// <summary>
/// 发送给js的消息
/// </summary>
public static Dictionary<string, Queue<string>> SendToJsMsg = new Dictionary<string, Queue<string>>();
/// <summary>
/// 初始化服务
/// </summary>
/// <param name="port"></param>
public void InitServer(string port, DealRequestMsg dealMasg)
{
DealMasg = dealMasg;
if (CheckCert("E=xxpt@xxx.com.cn, CN=xx.xx.com.cn, OU=xx, O=xx, L=xx, S=BeiJing, C=CN") == false)
{
InstallCACert(port);
}
//提供一个简单的、可通过编程方式控制的 HTTP 协议侦听器。此类不能被继承。
httpobj = new HttpListener();
//定义url及端口号,通常设置为配置文件
httpobj.Prefixes.Add("https://+:"+port+"/");
//启动监听器
httpobj.Start();
//异步监听客户端请求,当客户端的网络请求到来时会自动执行Result委托
//该委托没有返回值,有一个IAsyncResult接口的参数,可通过该参数获取context对象
httpobj.BeginGetContext(HttpResult, null);
}
/// <summary>
/// 检查证书
/// </summary>
/// <param name="CN"></param>
/// <returns></returns>
private static bool CheckCert(string CN)
{
bool flag = false;
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
try
{
store.Open(OpenFlags.MaxAllowed);
X509Certificate2Enumerator enumerator = store.Certificates.GetEnumerator();
while (enumerator.MoveNext())
{
X509Certificate2 current = enumerator.Current;
if (current.SubjectName.Name == CN)
{
flag = true;
return flag;
}
}
}
finally
{
store.Close();
}
return flag;
}
/// <summary>
/// 安装证书
/// </summary>
/// <param name="port"></param>
/// <returns></returns>
private bool InstallCACert(string port)
{
string s = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "dotnet.linux.pfx");
X509KeyStorageFlags machineKeySet = X509KeyStorageFlags.MachineKeySet;
X509Certificate2 certificate = new X509Certificate2(s, "mypassword", machineKeySet);
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.MaxAllowed);
store.Add(certificate);
store.Close();
if (Environment.OSVersion.Version.Major > 5)
{
string str2 = "0.0.0.0:" + port;
string cmd = string.Format("netsh http add sslcert ipport={0} certhash={1} appid={{391d625b-f844-4e72-a0b1-1ce1592b31eb}}", str2, certificate.Thumbprint);
string str4 = Run(cmd);
}
return true;
}
/// <summary>
/// 运行cmd
/// </summary>
/// <param name="cmd">命令</param>
/// <returns></returns>
public string Run(string cmd)
{
Process process1 = new Process();
process1.StartInfo.FileName = "cmd.exe";
process1.StartInfo.UseShellExecute = false;
process1.StartInfo.RedirectStandardInput = true;
process1.StartInfo.RedirectStandardOutput = true;
process1.StartInfo.RedirectStandardError = true;
process1.StartInfo.CreateNoWindow = true;
Process process = process1;
process.Start();
cmd = string.IsNullOrEmpty(cmd) ? "exit" : ("if 1 equ 1 (" + cmd + ") & exit");
process.StandardInput.WriteLine(cmd);
process.StandardInput.AutoFlush = true;
return "";
}
/// <summary>
/// 接收http请求
/// </summary>
/// <param name="args"></param>
private void HttpResult(IAsyncResult args)
{
//继续异步监听
httpobj.BeginGetContext(HttpResult, null);
var guid = Guid.NewGuid().ToString();
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine("接到新的请求:"+guid+",时间:"+DateTime.Now.ToString());
//获得context对象
var context = httpobj.EndGetContext(args);
var request = context.Request;
var response = context.Response;
//允许跨域
response.AddHeader("Access-Control-Allow-Origin", "*");
response.AddHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS");
response.AddHeader("Access-Control-Allow-Headers", "Content-Type,content-type,x-requested-with,NotReturn-Type");
context.Response.ContentType = "text/plain;charset=UTF-8";
context.Response.AddHeader("Content-type", "text/plain");
context.Response.ContentEncoding = Encoding.UTF8;
string returnObj = null;
if (request.HttpMethod == "POST" && request.InputStream != null)
{
//处理客户端发送的请求并返回处理信息
returnObj = HandleRequest(request, response);
}
else
{
returnObj = "Welcome to use the https print call channel, the service is published on port 18082";
}
var returnByteArr = Encoding.UTF8.GetBytes(returnObj);//设置客户端返回信息的编码
try
{
using (var stream = response.OutputStream)
{
//把处理信息返回到客户端
stream.Write(returnByteArr, 0, returnByteArr.Length);
}
}
catch (Exception ex)
{
}
}
/// <summary>
/// 处理请求
/// </summary>
/// <param name="request"></param>
/// <param name="response"></param>
/// <returns></returns>
private string HandleRequest(HttpListenerRequest request, HttpListenerResponse response)
{
string str = null;
try
{
var byteList = new List<byte>();
var byteArr = new byte[2048];
int readLen = 0;
int len = 0;
//接收客户端传过来的数据并转成字符串类型
do
{
readLen = request.InputStream.Read(byteArr, 0, byteArr.Length);
len += readLen;
byteList.AddRange(byteArr);
}
while (readLen != 0);
str = Encoding.UTF8.GetString(byteList.ToArray(), 0, len);
//调用处理
if (DealMasg != null && str!="")
{
DealMasg(str,request,response);
}
//看有没有积压的消息
if (ZLZHttpsServer.SendToJsMsg.ContainsKey(request.Url.ToString()))
{
Queue<string> quen = ZLZHttpsServer.SendToJsMsg[request.Url.ToString()];
if (quen.Count > 0)
{
string onemsg = quen.Dequeue();
return onemsg;
}
}
return "zlz-httpsret";
}
catch (Exception ex)
{
response.StatusDescription = "404";
response.StatusCode = 404;
return "在接收数据时发生错误:"+ex.Message;
}
response.StatusDescription = "200";
response.StatusCode = 200;
return "接收数据完成";
}
}
}
测试效果