目录
HttpServer 静态下载
先来看一段代码,启动一个静态的http服务
import CBHttp.code function main(parm) { var httpServer = new HttpServer(); httpServer.startServer(); while(1)//主线程不能退出 { Sleep(1000); } }服务启动好了,假设我们的项目根目录是E:\cbrotherwork\httpserver,那么我们的服务根路径就默认是E:\cbrotherwork\httpserver\webroot
我们新建txt文件E:\cbrotherwork\httpserver\webroot\111.txt,在文本里输入内容Hello HttpServer!。
然后我们打开本机浏览器输入::8000/111.txt,你发现你在网页上访问到了111.txt
主流的文件格式都支持下载
MIME控制
静态下载的过程中,有时需要控制可下载的文件格式,那么就要手动调配MIME
import CBHttp.code function main(parm) { var httpServer = new HttpServer(); httpServer.addMIME("mystyle","text/html");//添加后缀名为.mystyle,mime为text/html httpServer.addMIME("c"); //添加后缀名为.c,mime类型让系统自动识别 httpServer.removeMIME("gif"); //删除gif var mimiemap = httpServer.getMIME(); //获取目前支持的mime类型 mimiemap.begin(); do { print mimiemap.getKey() + ":" + mimiemap.getValue(); } while(mimiemap.next()); httpServer.startServer(); while(1) { Sleep(1000); } }运行结果:
rar:application/octet-stream bmp:image/bmp xml:application/xml html:text/html c:text/plain js:application/x-javascript txt:text/plain ico:image/x-icon zip:application/zip jpg:image/jpeg mystyle:text/html 7z:application/octet-stream json:application/json swf:application/x-shockwave-flash css:text/css png:image/pngHttpServer 动态接口
我们通常需要在用户调用一个接口时通过一些条件来返回不同的内容,下面我们再通过一段代码看一下
import CBHttp.code class HelloAction { function DoAction(request,respon) //这个函数写法是固定的,request表示客户端请求信息,respon是回复给客户机的信息 { var myTime = new Time(); respon.write("now time is:" + myTime.strftime("%Y/%m/%d %H:%M:%S")); respon.flush(); } } function main(parm) { var httpServer = new HttpServer(); httpServer.addAction("hello.cb",new HelloAction()); //我们注册接口hello.cb,响应类是HelloAction httpServer.startServer(); while(1) //主线程不能退出 { Sleep(1000); } }然后我们浏览器输入::8000/hello.cb,每次访问返回的都是当前时间。
接口名字可以是任意字符串,官方建议用统一的后缀,方便跟其他web服务器协作。
HttpServer 接口
函数
描述
用法
addAction(name,actobj)
添加http响应接口,name为接口名字,actobj为响应的Action对象
httpServer.addAction("hello.cb",actobj)
startServer(port,listen_ip)
启动服务port: 监听端口,默认8000listen_ip:监听IP,不传值默认为0.0.0.0表示监听IPV4所有IP传值为字符串"::"表示监听IPV6全部IP传值为字符串"*"表示监听IPV6与IPV4的全部IP
httpServer.startServer(port,listen_ip)
stopServer()
停止服务
httpServer.stopServer()
setRoot(path)
设置服务器跟目录,path: 根目录绝对路径
httpServer.setRoot(path)
setThreadCount(cnt)
设置响应线程数量,默认10个设置大了并发量大但是消耗资源多
httpServer.setThreadCount(50)
setNormalAction(actName)
设置默认响应接口访问后面不带路径时默认执行到的界面
httpServer.setNormalAction("hello.cb")httpServer.setNormalAction("hello.html")
set404Action(actName)
设置错误响应接口,不设置CBrother有默认页面
httpServer.set404Action("404.cb")
setOutTime(t)
设置请求超时时间,默认10秒,单位为秒
httpServer.setOutTime(3)
setMaxReqDataLen(len)
设置客户机发送的最大请求数据长度,默认500K,参数单位为(字节)
httpServer.setMaxReqDataLen(1024 * 1024)
openLog()
打开日志,在webroot平级建立log目录默认关闭,建议打开
httpServer.openLog()
closeFileService()
关闭文件下载服务录
httpServer.closeFileService()
setHttpsCertFile(CRT_PATH,KEY_PATH)
设置https证书如果设置了证书,服务将为https协议,CRT_PATH: crt证书路径key: 证书路径证书与Nginx所需证书相同
httpServer.setHttpsCertFile("e:/a.crt","e:/a.key")
setWebSocketModule(name,wsmodule)
设置websocket模块来支持websocket协议name: 接口名字wsmodule:websocket模块对象
httpServer.setWebSocketModule(name,wsmodule)
getMIME()
获取服务目前支持的mime格式,返回一个map对象,key为扩展,value为类型
var map = httpServer.getMIME()
addMIME(ext,type)
添加mime类型,ext: 扩展名type:类型,type不传值系统会自动识别
httpServer.addMIME("txt");httpServer.addMIME("mystyle","text/plain");
removeMIME(ext)
移除mime类型,ext为扩展名
httpServer.removeMIME("txt");
除了stopServer,其他接口都应该在startServer之前调用。
HttpServer 响应Action类
响应类必须要有function DoAction(request,respon)函数,如果没有会注册失败。
这个方法会被多线程调用,如果要访问公共资源需要加锁。
·request记录了客户端请求的信息
函数
描述
用法
getUrl()
获取请求的路径
var url = request.getUrl()
getProperty(name)
获取HTTP头里的参数
var v = request.getProperty("Content-Type")
getAllProperty()
获取HTTP头里的所有的参数,返回一个Map对象
var proMap = request.getAllProperty()
getParm(name)
获取请求链接?后面的参数,127.0.0.1?k=v&k1=1
var v = request.getParm("k")
getParmInt(name)
获取请求链接?后面的参数,强转整形
var v = request.getParmInt("k1")
getAllParm()
获取请求链接?后面的所有参数,返回一个Map对象
var parmMap = request.getAllParm()
getData()
获取请求post的数据
var data = request.getData()
getRemoteIP()
获取客户机IP
var ip = request.getRemoteIP()
getMethod()
获取请求类型,"GET"或"POST"
var method = request.getMethod()
getCookieCount()
获取cookie数量
var cnt = request.getCookieCount()
getCookie(index)
根据索引获取cookie,返回cookie对象
var cookie = request.getCookie(0)
getCookie(cookieName)
根据名字获取cookie,如果有重名的cookie返回第一个
var cookie = request.getCookie("userName")
getFormData()
获取form表单数据,当客户端以form表单格式提交才返回FormData对象,否则返回null
var formdata = request.getFormData()
isKeepAlive()
客户端请求是否为保持连接状态,true为保持连接,false为立即关闭
var isKeep = request.isKeepAlive()
isHttps()
客户端请求是否为https,true为https,false为http
var isKeep = request.isHttps()
·respon是返回给客户端的信息
函数
描述
用法
addProperty(key,value)
添加http头数据,必须为字符串
respon.addProperty("Access-Control-Allow-Origin","*")
addCookie(cookie)
添加cookie
respon.addCookie(new Cookie("aaa","bbb"))
setStatus(status)
设置返回http状态
respon.setStatus(200)
write(data)
写入要返回数据
respon.write("hello")
flush()
发送数据
respon.flush()
Cookie 类
在日常开发中,服务器需要通过cookie来判别客户机身份,CBrother提供了Cookie类来描述http头中的Set-Cookie与Cookie字段
函数
描述
用法
setName(name)
设置cookie的名称
myCookie.setName("aaa")
setValue(v,pwd)
设置cookie的字段,pwd不传为明文,传入密码会增加一个签名
myCookie.setValue("bbb")myCookie.setValue("bbb","pwdstr")
getName()
获取cookie的名称
var name = myCookie.getName()
getValue(pwd)
获取cookie的字段,pwd不传返回原文,传入密码会检查签名
var cookie = myCookie.getValue()var cookie = myCookie.setValue("pwdstr")
setPath(path)
设置cookie的有效路径,不设置默认为/
myCookie.setPath("/aa/cc/")
setDomain(domain)
设置cookie的域,默认为空
myCookie.setDomain("cbrother.net")
setExpires(timeSeconds)
设置cookie有效时间,单位为秒,设置为0表示删除cookie,默认浏览器关闭失效
myCookie.setExpires(300)
setHttpOnly(boolValue)
cookie的HttpOnly标签,默认false
myCookie.setHttpOnly(true)
getPath()
获取cookie的有效路径
var path = myCookie.getPath()
getDomain()
获取cookie的域
var domain = myCookie.getDomain()
getExpires()
获取cookie有效时间
var t = myCookie.getExpires()
getHttpOnly()
获取cookie的HttpOnly标签
var httponly = myCookie.getHttpOnly()
其中带密码的setValue方法会用密码和原始明文算一个md5值作为cookie签名,这样保证了cookie不可被伪造,一般可以用于登陆状态验证。当然,在一些安全性要求比较高的场景,开发者也可以自己实现安全级别更高的cookie加密验证方式。
通过一个段代码来学习一下Cookie的用法:
class CookieAction { function DoAction(request,respon) { var cookieCnt = request.getCookieCount();//获取客户机Cookie数量 if(cookieCnt > 0) { for(var i = 0 ; i < cookieCnt ; i++)//遍历的方式可以获取所有的Cookie,包括名字相同的Cookie { //客户机已经有cookie var cookie = request.getCookie(i); if(cookie.getName() == "pwdCookie") { print cookie.getValue(); print cookie.getValue("pwd222");//带密码的cookie } else { print cookie.getValue();//明文cookie } } var pwdCookie request.getCookie("pwdCookie");//根据名字获取Cookie,如果有同名Cookie则只返回第一个 print pwdCookie.getValue("pwd222"); } else { //客户机没有cookie var cookie = new Cookie("normalCookie","3333"); respon.addCookie(cookie);//添加明文cookie cookie = new Cookie(); cookie.setName("pwdCookie"); cookie.setValue("3333","pwd222"); respon.addCookie(cookie);//添加带密码的cookie } var myTime = new Time(); respon.write("now time is:" + myTime.strftime("%Y/%m/%d %H:%M:%S")); respon.flush(); } }表单FormData 类
CBrother提供了FormData类来描述form表单数据
函数
描述
用法
getType()
获取表单enctype类型,FORM_WWW_URLENCODED表示application/x-www-form-urlencoded,FORM_MULTI_PART表示multipart/form-data。在lib/htppdef里定义
var t = form.getType()
getTextCnt()
获取type不为"file"的input数量
var cnt = form.getTextCnt()
getText(index)
根据坐标获取input的value,type为file获取不到
var value = form.getText(0)
getText(name)
根据name获取input的value,type为file获取不到
var value = form.getText("txt1")
getTextName(index)
根据坐标获取input的name,type为file获取不到
var name = form.getTextName(0)
getMultiPartCnt()
当form的enctype为FORM_MULTI_PART时候,获取input数量
var cnt = form.getMultiPartCnt()
getMultiPart(index)
根据坐标获取input数据,返回Multipart对象
var data = form.getMultiPart(0)
getMultiPart(name)
根据name获取input数据,返回Multipart对象
var data = form.getMultiPart("file")
addText(name,str)
添加一个文本类型的input数据,name为名称,str为内容.根HttpClientRequest向其他服务器发起请求的时候使用
form.addText("111","111")
addFile(name,filename,data,mime)
添加一个文件类型的input数据,name为名称,filename为文件名,data为文件内容string或ByteArray对象,mime为文件mime类型,不传值会自动识别
form.addFile("file1","222.txt","222")
比如web前端提交的form表单结构如下:
<form method="post" action="form.cb" > <input type="text" name="txt1"> <input type="text" name="txt2"> <input type="password" name="userpass" <input type="radio" name="sex" value="man" checked>man <input type="radio" name="sex" value="woman">woman <input type="file" name="file" value="hiddenvalue" multiple="multiple"/> <input type="submit" value="提交(提交按钮)"> </form>网页展示效果如下:
因为这个表单没有指定enctype,所以Content-Type为application/x-www-form-urlencoded,我们日常使用到的大部分表单都是这种格式。当前端post提交后服务器使用如下方式获取表单数据
class FormAction { function DoAction(request,respon) { print request.getData();//打印发送的数据 print "**********************分割线*******************************"; var formdata = request.getFormData(); if(formdata == null) { return; //只有Content-Type为application/x-www-form-urlencoded或者multipart/form-data时候才会返回FormData对象,否则返回null } var type = formdata.getType(); if(type == FORM_WWW_URLENCODED) //Content-Type为application/x-www-form-urlencoded类型的表单 { var textCnt = formdata.getTextCnt(); for(var i = 0 ; i < textCnt ; i++) { print formdata.getTextName(i) + ":" + formdata.getText(i); } } } }服务器输出结果:
txt1=111&txt2=222&userpass=333&sex=man&file=111.txt **********************分割线******************************* txt1:111 txt2:222 userpass:333 sex:man file:111.txtMultipart 类
这里需要学习一下form添加enctype=multipart/form-data时提交的报文格式
Multipart类来描述form表单在multipart/form-data数据类型下的一个input数据,这个类型的表单一般用在上传文件
函数
描述
用法
getParm(name)
获取Multipart段落内的参数
var parm = mulpart.getParm("name")
getData(isByte)
获取Multipart的数据,isByte不传值,默认返回字符串,传true返回ByteArray对象
var data = mulpart.getData()var bytearry = mulpart.getData(true)
getDataLen()
获取数据长度
var len = mulpart.getDataLen()
isFile()
如果是文件类型,返回true
var isfile = mulpart.isFile()
getFileCount()
获取这个input上传了几个文件
var cnt = mulpart.getFileCount()
getFile(index)
获取文件对应数据,返回一个Multipart对象
var filedata = mulpart.getFile(0)
比如web前端提交的form表单结构如下:(只是添加了一个enctype="multipart/form-data")
<form method="post" action="form.cb"enctype="multipart/form-data"> <input type="text" name="txt1"> <input type="text" name="txt2"> <input type="password" name="userpass" <input type="radio" name="sex" value="man" checked>man <input type="radio" name="sex" value="woman">woman <input type="file" name="file" value="hiddenvalue" multiple="multiple"/> <input type="submit" value="提交(提交按钮)"> </form>网页展示效果没有变化如下:
添加了enctype,Content-Type变成multipart/form-data,服务器使用如下方式获取表单数据
class FormAction { function DoAction(request,respon) { print request.getData();//打印发送的数据 print "**********************分割线*******************************"; var formdata = request.getFormData(); if(formdata == null) { return; //只有Content-Type为application/x-www-form-urlencoded或者multipart/form-data时候才会返回FormData对象,否则返回null } var type = formdata.getType(); if(type == FORM_MULTI_PART) //Content-Type为multipart/form-data类型的表单 { var formcnt = formdata.getMultiPartCnt(); for(var i = 0 ; i < formcnt ; i++) { var muldata = formdata.getMultiPart(i); if(muldata.isFile())//如果是上传的文件 { for(var j = 0 ; j < muldata.getFileCount() ; j++) { //上传的文件可以在这里通过File对象把数据保存到文件里,CBrother目录下sample/http/httpserver_form.cb里面有例子,这里只是把数据打印出来 var filedata = muldata.getFile(j); print filedata.getParm("name") + " " + filedata.getParm("filename") + ": size=" + filedata.getDataLen() + " value=" + filedata.getData(); } } else { print muldata.getParm("name") + ":" + muldata.getData(); } } } } }服务器运行结果如下:
------WebKitFormBoundaryw7KfcBx8f23zh8d4 Content-Disposition: form-data; name="txt1" 111 ------WebKitFormBoundaryw7KfcBx8f23zh8d4 Content-Disposition: form-data; name="txt2" 222 ------WebKitFormBoundaryw7KfcBx8f23zh8d4 Content-Disposition: form-data; name="userpass" ------WebKitFormBoundaryw7KfcBx8f23zh8d4 Content-Disposition: form-data; name="sex" man ------WebKitFormBoundaryw7KfcBx8f23zh8d4 Content-Disposition: form-data; name="file"; filename="111.txt" Content-Type: text/plain iam 111.txt file value! ------WebKitFormBoundaryw7KfcBx8f23zh8d4-- **********************分割线******************************* txt1:111 txt2:222 userpass: sex:man file 111.txt: size=24 value=iam 111.txt file value!HttpClientRequest 主动发起请求
在开发过程中,我们经常会遇到与第三方服务器通信,这时候就需要主动请求第三方服务器接口,CBrother提供了HttpClientRequest来主动访问别人提供的http和https接口
var myReq = new HttpClientRequest();函数
描述
用法
setMethod(method)
设置请求方式,"GET"或者"POST",类型字符串
myReq.setMethod("POST")
setUrl(url)
设置请求地址,参数地址全路径
myReq.setUrl("/hello.cb")myReq.setUrl("")
addProperty(key,value)
添加http头,必须都为字符串
myReq.addProperty("HOST","127.0.0.1")
getProperty(key)
获取HTTP头里的参数,返回值为字符串
var v = myReq.getProperty("Content-Type")
getAllProperty()
获取HTTP头里的所有的参数,返回一个Map对象
var proMap = myReq.getAllProperty()
addParm(key,value)
在链接上添加参数,必须都为字符串。会在链接地址后面追加?k1=v1&k2=v2
myReq.addParm("11","121")
getParm(key)
获取已经添加的参数
var v = myReq.getParm("k")
getAllParm()
获取已经添加的参数,返回一个Map对象
var parmMap = myReq.getAllParm()
addData(data)
添加要提交的数据,data为要提交的数据,必须都为字符串
myReq.addData("")
flush()
发起请求,返回HttpClientResponse对象
var response = myReq.flush()
setOutTime(seconds)
设置超时时间,单位为秒
myReq.setOutTime(5)
setKeepAlive(isKeep)
设置是否保持与服务器连接,不设置默认false不保持
myReq.setKeepAlive(true)
reset(clearHead = true)
还原成一个新的请求对象,仅保留网络连接。开启keepalive以此来复用网络,clearHead传值为false则不清理已经添加的http头
myReq.reset()
close()
如果开启了keepalive,则主动关闭与服务器链接,不开启没意义
myReq.close()
addFormData(enctype)
本次请求添加form表单数据enctype为FORM_WWW_URLENCODED或者FORM_MULTI_PART,定义在lib/httpdef里,返回FormDatad对象
var formdata = myReq.addFormData(FORM_WWW_URLENCODED)var formdata = myReq.addFormData(FORM_MULTI_PART)
addCookie(cookie)
添加一个cookie
myReq.addCookie(new Cookie("aaa","bbb"))
getCookieCount()
获取添加cookie数量
var cnt = myReq.getCookieCount()
getCookie(index)
根据索引获取cookie
var cookie = myReq.getCookie(index)
getCookie(cookieName)
根据名字获取cookie
var cookie = myReq.getCookie("cookieName")
setProxy(proxyType,ip,port,acc,pwd)
设置代理,proxyType为"http","https","socket5"中的一种。ip,port为代理服务器IP,如果服务器需要验证用户名,最后两个参数需要写帐号密码
myReq.setProxy("socket5","111.111.111.111",4646)myReq.setProxy("https","111.111.111.111",4646,"user","123")
HttpClientResponse为主动请求后返回的结果,HttpClientRequest的flush方法会返回一个HttpClientResponse对象
var myReq = new HttpClientRequest(); myReq.setMethod("GET"); myReq.setUrl(""); var myResponse = myReq.flush();函数
描述
用法
getStatus()
获取状态码
var staus = myResponse.getStatus()
getProperty(name)
获取HTTP头里的参数,返回值为字符串
var v = myResponse.getProperty("Content-Type")
getAllProperty()
获取HTTP头里的所有的参数,返回一个Map对象
var proMap = myResponse.getAllProperty()
getData()
获取返回的数据
var data = myResponse.getData()
getCookieCount()
获取cookie数量
var cnt = myResponse.getCookieCount()
getCookie(index)
根据索引获取cookie对象
var cookie = myResponse.getCookie(0)
getCookie(cookieName)
根据名字获取cookie对象
var cookie = myResponse.getCookie("cookieName")
例子:
import CBHttp.code function main(parm) { var myReq = new HttpClientRequest(); myReq.setMethod("GET"); myReq.setUrl(""); var myRes = myReq.flush(); print myRes.getStatus(); print myRes.getData(); }结果:
200 <html> <head> <script> location.replace(location.href.replace("https://","http://")); </script> </head> <body> <noscript><meta http-equiv="refresh" content="0;url="></noscript> </body> </html>在开发过程中,为了降低服务器压力,经常需要用到keepalive来保持连接多次请求,看下面的例子:
import CBHttp.code import lib/httpdef function main(parm) { var myReq = new HttpClientRequest(); myReq.setMethod(HTTP_GET); myReq.setUrl(""); myReq.setKeepAlive(true); //开启keepalive,如果没有这一句默认是请求完毕后自动关闭连接 var myRes = myReq.flush(); print myRes.getStatus(); print myRes.getData(); myReq.reset(); //重置请求对象,仅保留网络连接,如果因为超时连接被服务器主动关闭,那么第二次请求会重新创建连接 myReq.setMethod(HTTP_GET); myReq.setUrl("/doc.html"); var myRes = myReq.flush(); //第二次请求没有开启keepalive,所以这句执行完后连接就会关闭了 print myRes.getStatus(); print myRes.getData(); }客户端使用Cookie例子:
function main(parm) { var myReq = new HttpClientRequest(); myReq.setMethod("GET"); myReq.setUrl(""); myReq.addCookie(new Cookie("aaa","bbb"));//本次请求添加cookie var myRes = myReq.flush(); var cookieCnt = myRes.getCookieCount();//服务器返回的cookie信息 for(var i = 0 ; i < cookieCnt ; i++) { var cookie = request.getCookie(i); print cookie.getName(); print cookie.getValue(); } }客户端模拟form表单的例子:
import lib/httpdef function main(parm) { var clientReq = new HttpClientRequest(); clientReq.setMethod(HTTP_POST); clientReq.setUrl(":8003/form.cb"); var formdata = clientReq.addFormData(FORM_MULTI_PART); //也可以用FORM_WWW_URLENCODED,FORM_WWW_URLENCODED类型不支持上传文件 formdata.addText("111","111"); formdata.addText("222","222"); formdata.addFile("file","111.txt","222"); formdata.addFile("file","222.txt","34567"); clientReq.flush(); }HttpServer同一个端口支持多个不同内容的网站
如果需要在一台服务上同时布置多个网站,则需要在调用HttpServer下面几个接口时第二个参数传入网站的域名即可
函数
描述
用法
setRoot(path,domain)
设置域名跟目录
httpServer.setRoot(path,"www.cbrother.net")
setNormalAction(actName,domain)
设置域名默认响应接口
httpServer.setNormalAction("hello.cb","www.cbrother.net")
set404Action(actName,domain)
设置域名错误界面接口,不设置有默认页面
httpServer.set404Action("404.cb","www.cbrother.net")
setHttpsCertFile(CRT_PATH,KEY_PATH,domain)
设置https证书,如果设置了证书,该域名才可支持https协议
httpServer.setHttpsCertFile("e:/a.crt","e:/a.key","www.cbrother.net")
比如同一台服务器支持了www.a.com,www.b.com,www.c.com3个域名的网站
function main(parm) { var httpServer = new HttpServer(); httpServer.setRoot("c:/web" ); //设置服务器默认根目录为c:/web httpServer.addAction("hello.cb",new HelloAction()); httpServer.addAction("404.cb",new My404Action()); httpServer.setNormalAction("hello.cb"); //设置服务器默认响应为hello.cb httpServer.set404Action("404.cb"); //设置服务器默认404页面 httpServer.addAction("a_hello.cb",new A_HelloAction()); httpServer.setRoot("c:/webA","www.a.com"); //www.a.com网站根目录变化为c:/webA,www.b.com与www.c.com根目录依旧为c:/web httpServer.setNormalAction("a_hello.cb","www.a.com"); //www.a.com网站默认页面变化为a_hello.cb, www.b.com与www.c.com默认页依旧为hello.cb //www.a.com,www.b.com,ww.c.com都没有设置404页面,所以都默认执行404.cb httpServer.startServer(80); //启动http服务 //---------------------------再启动一个https服务,代码复制一遍,添加证书接口和端口 var httpServerHttps = new HttpServer(); httpServerHttps.setRoot("c:/web"); httpServerHttps.addAction("hello.cb",new HelloAction()); httpServerHttps.addAction("404.cb",new My404Action()); httpServerHttps.setNormalAction("hello.cb"); httpServerHttps.set404Action("404.cb"); httpServerHttps.setHttpsCertFile("e:/normal.crt","e:/normal.key"); //设置https服务默认证书 httpServerHttps.addAction("a_hello.cb",new A_HelloAction()); httpServerHttps.setRoot("c:/webA","www.a.com"); httpServerHttps.setNormalAction("a_hello.cb","www.a.com"); httpServerHttps.setHttpsCertFile("e:/AAA.crt","e:/AAA.key","www.a.com"); //www.a.com证书使用e:/AAA.crt和e:/AAA.key,www.b.com与www.c.com依旧使用默认证书e:/normal.crt和e:/normal.key httpServer.startServer(443); //启动https服务 //-----------------------------https结束 while(1) { Sleep(1000); } }如此便实现了同服务器同端口支持多个网站并且同时支持http与https协议