2024-10-26 16:36:57 +08:00
|
|
|
|
import https from 'node:https';
|
|
|
|
|
|
import fs from 'fs';
|
|
|
|
|
|
import { Application } from '@midwayjs/koa';
|
|
|
|
|
|
import { createSelfCertificate } from './self-certificate.js';
|
2025-04-30 09:38:44 +08:00
|
|
|
|
import {logger, safePromise} from '@certd/basic';
|
2024-10-26 16:36:57 +08:00
|
|
|
|
|
|
|
|
|
|
export type HttpsServerOptions = {
|
|
|
|
|
|
enabled: boolean;
|
|
|
|
|
|
app?: Application;
|
2025-10-11 16:59:28 +08:00
|
|
|
|
hostname?: string;
|
2024-10-26 16:36:57 +08:00
|
|
|
|
port: number;
|
|
|
|
|
|
key: string;
|
|
|
|
|
|
cert: string;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2024-10-26 18:01:06 +08:00
|
|
|
|
export class HttpsServer {
|
|
|
|
|
|
server: https.Server;
|
|
|
|
|
|
opts: HttpsServerOptions;
|
|
|
|
|
|
constructor() {}
|
|
|
|
|
|
|
|
|
|
|
|
async restart() {
|
|
|
|
|
|
await this.close();
|
|
|
|
|
|
return this.start(this.opts);
|
2024-10-26 16:36:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-10-26 18:01:06 +08:00
|
|
|
|
async close() {
|
2025-04-30 09:38:44 +08:00
|
|
|
|
return safePromise((resolve, reject) => {
|
2024-10-26 18:01:06 +08:00
|
|
|
|
this.server.close(() => {
|
|
|
|
|
|
resolve(true);
|
|
|
|
|
|
});
|
2024-10-26 16:36:57 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
2024-10-26 18:01:06 +08:00
|
|
|
|
|
|
|
|
|
|
start(opts: HttpsServerOptions) {
|
|
|
|
|
|
if (!opts) {
|
|
|
|
|
|
logger.error('https配置不能为空');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
this.opts = opts;
|
|
|
|
|
|
logger.info('=========================================');
|
|
|
|
|
|
if (!opts.key || !opts.cert) {
|
|
|
|
|
|
logger.error('证书路径未配置,无法启动https服务,请先配置:koa.https.key和koa.https.cert');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!fs.existsSync(opts.key) || !fs.existsSync(opts.cert)) {
|
|
|
|
|
|
logger.info('证书文件不存在,将生成自签名证书');
|
|
|
|
|
|
createSelfCertificate({
|
|
|
|
|
|
crtPath: opts.cert,
|
|
|
|
|
|
keyPath: opts.key,
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
logger.info('准备启动https服务');
|
|
|
|
|
|
const httpServer = https.createServer(
|
|
|
|
|
|
{
|
|
|
|
|
|
cert: fs.readFileSync(opts.cert),
|
|
|
|
|
|
key: fs.readFileSync(opts.key),
|
|
|
|
|
|
},
|
|
|
|
|
|
opts.app.callback()
|
|
|
|
|
|
);
|
|
|
|
|
|
this.server = httpServer;
|
2025-10-11 16:59:28 +08:00
|
|
|
|
let hostname = opts.hostname || '::';
|
2024-10-26 18:01:06 +08:00
|
|
|
|
// A function that runs in the context of the http server
|
|
|
|
|
|
// and reports what type of server listens on which port
|
|
|
|
|
|
function listeningReporter() {
|
|
|
|
|
|
// `this` refers to the http server here
|
|
|
|
|
|
logger.info(`Https server is listening on https://${hostname}:${opts.port}`);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
httpServer.listen(opts.port, hostname, listeningReporter);
|
|
|
|
|
|
return httpServer;
|
|
|
|
|
|
} catch (e) {
|
2025-10-11 16:59:28 +08:00
|
|
|
|
if ( e.message?.includes("address family not supported")) {
|
|
|
|
|
|
hostname = "0.0.0.0"
|
|
|
|
|
|
logger.error(`${e.message},尝试监听${hostname}`, e);
|
|
|
|
|
|
try{
|
|
|
|
|
|
httpServer.listen(opts.port, hostname, listeningReporter);
|
|
|
|
|
|
return httpServer;
|
|
|
|
|
|
}catch (e) {
|
|
|
|
|
|
logger.error('启动https服务失败', e);
|
|
|
|
|
|
}
|
|
|
|
|
|
}else{
|
|
|
|
|
|
logger.error('启动https服务失败', e);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-10-26 18:01:06 +08:00
|
|
|
|
}
|
2024-10-26 16:36:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-10-26 18:01:06 +08:00
|
|
|
|
|
|
|
|
|
|
export const httpsServer = new HttpsServer();
|