wo-base-webserver/webserver.js

212 lines
9.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const fs = require('fs')
const path = require('path')
const express = require('express')
const coretool = require('wo-core-toolkit')
const wo = (global.wo = {
envar: require('wo-base-envar').merge_envar({
rawEnvar: {
commanderOptions: [
// 命令行里可以接受的参数。将传给 commander。每个参数的定义格式是 [参数名,参数键,描述],后两者用于传给 commander取值后覆盖掉同名变量。
['webProtocol', '-P, --webProtocol <string>', 'Web protocol: http|https|httpall.'],
['webHostname', '-H, --webHostname <string>', 'Host IP or domain name.'],
['webPort', '-p, --webPort <number>', 'HTTP port number.'],
['webRoot', '-w, --webRoot <string>', 'Path to serve as website.'],
['webSsl', '--webSsl <string>', 'SSL options in JSON string.'],
],
// 最基础的必须的默认配置,如果用户什么也没有提供
webProtocol: process.env.NODE_ENV === 'production' ? 'httpall' : 'http',
webHostname: process.env.NODE_ENV === 'production' ? 'unknownhost' : 'localhost',
webPort: process.env.NODE_ENV === 'production' ? coretool.PORT_WEB_SERVER_DEV : undefined,
webRoot: process.env.NODE_ENV === 'production' ? '_webroot' : 'unpackage/dist/build/web', // local path to serve as webroot. 'unpackage/dist/build/h5'
webIndex: 'index.html',
webSsl:
process.env.NODE_ENV === 'production'
? {
type: 'file', // greenlock or file
file: {
key: './ssl/privkey.pem', // ssl key file,
cert: './ssl/fullchain.pem', // ssl cert file,
ca: './ssl/chain.pem', // ssl ca file,
},
}
: undefined,
// 如果使用虚拟主机
/*
vhosts: [
{ webRoot: 'dist', webIndex: 'index.html', domainList: ['']}
],
*/
},
envarFiles: ['./envar-web.js', './envar-web.gitignore.js'],
}),
})
if (typeof wo.envar.webSsl === 'string') {
wo.envar.webSsl = eval(`(${wo.envar.webSsl})`)
}
console.log({ _at: new Date().toJSON(), about: '******** Environment Variables ********', envar: JSON.parse(coretool.stringify_by_keyorder(wo.envar)) })
;(function serve () {
console.log({ _at: new Date().toJSON(), about: '★★★★★★★★ Starting Server ★★★★★★★★' })
const server = express()
// const greenlock = require('greenlock-express').create({
// version: 'draft-11',
// server: 'https://acme-v02.api.letsencrypt.org/directory', // for test: acme-staging-v02
// agreeTos: true,
// communityMember: false,
// store: require('greenlock-store-fs'),
// email: 'ssl@faronear.org',
// approvedDomains: wo.envar.sslDomains,
// configDir: path.resolve(__dirname, 'ssl'),
// app: server,
// })
/*** 通用中间件 ***/
server.use(require('morgan')('dev'))
server.use(require('body-parser').json())
server.use(require('body-parser').urlencoded({ extended: false }))
server.use(require('cookie-parser')())
server.use(require('compression')())
/*** 路由 ***/
// vhost 匹配了域名就执行不匹配就next()
// express.static 找到了具体文件就返回找不到就next()
// 所以,如果 vhost匹配了域名且static找到了文件就结束了。如果 vhost 匹配了域名但static找不到文件就继续往下。
if (!wo.envar.vhosts) {
server.use(
express.static(path.join(process.cwd(), wo.envar.webRoot).replace('\\', '/'), { index: wo.envar.webIndex }) // 可以指定到 node应用之外的目录上。windows里要把 \ 换成 /。
)
//server.use(require('serve-favicon')(path.join(process.cwd(), wo.envar.webRoot, 'favicon.ico')))
} else {
let vhost = require('vhost')
for (let h of wo.envar.vhosts) {
for (let domain of h.domainList) {
server.use(
vhost(
domain,
express.static(path.join(process.cwd(), h.webRoot).replace('\\', '/'), { index: h.webIndex }) // 可以指定到 node应用之外的目录上。windows里要把 \ 换成 /。
)
)
}
}
}
/*** 路由 ***/
//var router = express.Router()
//router.get('/path', function(req,res) { res.redirect('target') })
//server.use(router)
/*** 启动 Web 服务 ***/
let webServer
if ('http' === wo.envar.webProtocol) {
let portHttp = wo.envar.webPort || 80
webServer = require('http')
.createServer(server)
.listen(portHttp, function (err) {
if (err) {
console.error({ _at: new Date().toJSON(), err })
} else {
console.log({ _at: new Date().toJSON(), about: `Server listening on ${wo.envar.webProtocol}://${wo.envar.webHostname}:${portHttp}` })
}
})
} else if ('https' === wo.envar.webProtocol) {
let portHttps = wo.envar.webPort || 443
webServer = require('https')
.createServer(
// wo.envar.webSsl.type==='greenlock' ? greenlock.httpsOptions :
{
key: fs.readFileSync(wo.envar.webSsl.file.key),
cert: fs.readFileSync(wo.envar.webSsl.file.cert),
// ca: [ fs.readFileSync(wo.envar.webSsl.file.ca) ] // only for self-signed certificate: https://nodejs.org/api/tls.html#tls_tls_createserver_options_secureconnectionlistener
},
server
)
.listen(portHttps, function (err) {
if (err) {
console.error({ _at: new Date().toJSON(), err })
} else {
console.log({ _at: new Date().toJSON(), about: `Server listening on ${wo.envar.webProtocol}://${wo.envar.webHostname}:${portHttps}` })
}
})
} else if ('httpall' === wo.envar.webProtocol) {
let portHttp = wo.envar.webPort?.portHttp || 80
let portHttps = wo.envar.webPort?.portHttps || 443
// if (wo.envar.webSsl.type==='greenlock') {
// greenlock.listen(portHttp, portHttps, function (err) {
// if (err) console.error({ _at: new Date().toJSON(),err})
// else console.log({ _at: new Date().toJSON(), about: `Server listening on [${wo.envar.webProtocol}] http=>https://${wo.envar.webHostname}:${portHttp}=>${portHttps} for ${server.settings.env} environment`})
// })
// }else {
require('http')
.createServer(function (ask, reply) {
reply.writeHead(301, { Location: `https://${ask.headers.host.replace(`:${portHttp}`, `:${portHttps}`)}${ask.url}` })
reply.end()
})
.listen(portHttp, function (err) {
if (err) {
console.error({ _at: new Date().toJSON(), err })
} else {
console.log({ _at: new Date().toJSON(), about: `Server redirecting from http://${wo.envar.webHostname}:${portHttp}` })
}
})
webServer = require('https')
.createServer(
{
key: fs.readFileSync(wo.envar.webSsl.file.key),
cert: fs.readFileSync(wo.envar.webSsl.file.cert),
// ca: [ fs.readFileSync(wo.envar.webSsl.file.ca) ] // only for self-signed certificate: https://nodejs.org/api/tls.html#tls_tls_createserver_options_secureconnectionlistener
},
server
)
.listen(portHttps, function (err) {
if (err) {
console.error({ _at: new Date().toJSON(), err })
} else {
console.log({ _at: new Date().toJSON(), about: `Server listening on https://${wo.envar.webHostname}:${portHttps}` })
}
})
// }
} else if ('redirectHttp2Https' === wo.envar.webProtocol) {
let portHttp = wo.envar.webPort?.portHttp || 80
let portHttps = wo.envar.webPort?.portHttps || 443
webServer = server
.all('*', function (ask, reply) {
reply.redirect(301, `https://${ask.headers.host.replace(`:${portHttp}`, `:${portHttps}`)}${ask.url}`)
})
.listen(portHttp, function (err) {
if (err) {
console.error({ _at: new Date().toJSON(), err })
} else {
console.log({ _at: new Date().toJSON(), about: `Server listening on ${wo.envar.webProtocol}://${wo.envar.webHostname}:${portHttp}` })
}
})
} else if ('proxyHttps2Http' === wo.envar.webProtocol) {
let portHttp = wo.envar.webPort?.portHttp || 80
let portHttps = wo.envar.webPort?.portHttps || 443
var proxy = require('http-proxy').createProxyServer({
ssl: {
key: fs.readFileSync(wo.envar.webSsl.file.key),
cert: fs.readFileSync(wo.envar.webSsl.file.cert),
// ca: [ fs.readFileSync(wo.envar.sslCA) ] // https://nodejs.org/api/tls.html#tls_tls_createserver_options_secureconnectionlistener
},
target: `http://127.0.0.1:${portHttp}`, // iOS 的 AppStore 要求支持IPv6只能用国外的vultr.com服务器因此再代理回国内的solet主机。
// secure: true, // proxying https to https
ws: true, // proxying websockets
})
proxy.on('error', function (err, req, res) {
res.writeHead(500, { 'Content-Type': 'text/plain' })
res.end('Proxy Error.')
})
proxy.listen(portHttps, function (err) {
if (err) {
console.error({ _at: new Date().toJSON(), err })
} else {
console.log({ _at: new Date().toJSON(), about: `Server listening on ${wo.envar.webProtocol}://${wo.envar.webHostname}:${portHttps}` })
}
})
}
return webServer
})()