flaunt-web/service/core/router/index.cjs

193 lines
6.7 KiB
JavaScript

const logger = require('../utils/log.cjs')
const routes = require('./routes.cjs')
const httpProxy = require('http-proxy')
const proxy = httpProxy.createProxyServer({})
const fs = require('fs')
const url = require('url')
const axios = require('axios')
const dist = 'dist'
let mime
import('mime').then((res) => {
mime = res.default
})
let proxys = require('../../../src/proxy.cjs')
const { Exception } = require("sass");
const httpOk = 200
const httpBadRequest = 400
const matchProxy = (request, response) => {
const match = request.url.split('/')[1]
const proxyInfo = proxys['/' + match]
if (proxyInfo) {
const host = request.headers.host;
delete request.headers.host
if (typeof proxyInfo.rewrite === 'function') {
request.url = proxyInfo.rewrite(request.url)
}
proxy.web(request, response, {
target: proxyInfo.target || ("http://" + host),
changeOrigin: proxyInfo.changeOrigin
})
logger.info(`${request.method} ${httpOk} ${request.url}`)
return true
} else {
return null
}
}
const matchRouter = async (request, response) => {
let [url] = request.url.split('?')
let route = routes
let url_sp = url.split('/')
for (let p of url_sp) {
if (!p) {
continue
}
if (route[p]) {
route = route[p]
} else {
return false
}
}
if (typeof route === 'function') {
await route(request, response)
// response.writeHead(httpOk, { 'Content-Type': 'application/json' })
// response.end(JSON.stringify(res))
logger.info(`${request.method} ${httpOk} ${request.url}`)
return true
} else {
return false
}
}
function getMimeType(filePath) {
const ext = filePath.split('.').pop()?.toLowerCase()
const defaultMimes = {
png: 'image/png',
jpg: 'image/jpeg',
jpeg: 'image/jpeg',
gif: 'image/gif',
webp: 'image/webp',
svg: 'image/svg+xml',
ico: 'image/x-icon',
js: 'text/javascript',
css: 'text/css',
html: 'text/html',
json: 'application/json',
woff: 'font/woff',
woff2: 'font/woff2',
ttf: 'font/ttf',
otf: 'font/otf'
}
if (ext && defaultMimes[ext]) {
return defaultMimes[ext]
}
if (mime && typeof mime.getType === 'function') {
return mime.getType(filePath) || 'application/octet-stream'
}
return 'application/octet-stream'
}
const matchFile = async (request, response) => {
return new Promise((resolve) => {
const cleanPath = decodeURIComponent(request.url.split('?')[0])
fs.readFile(dist + cleanPath, (err, file) => {
if (!err) {
const mimetype = getMimeType(cleanPath)
const responseHdeaders = { 'Content-Type': mimetype }
if (cleanPath.endsWith("-sw.js")) {
responseHdeaders["Service-Worker-Allowed"] = '/'
}
response.writeHead(httpOk, responseHdeaders)
response.end(file)
// logger.info(`${request.method} ${httpOk} ${request.url}`)
resolve(true)
} else {
resolve(false)
}
})
})
}
const endIndex = async (request, response) => {
fs.readFile(dist + '/index.html', 'utf-8', async (err, html) => {
if (!err) {
let finalHtml = html
try {
const parsedUrl = url.parse(request.url, true)
if (parsedUrl.pathname === '/article-detail' && parsedUrl.query.id) {
const id = parsedUrl.query.id
const res = await axios.get(`http://wechat.wenyitu.com/api/articles/${id}`)
const article = res.data
if (article) {
if (article.title) {
finalHtml = finalHtml.replace(/<title>.*?<\/title>/, `<title>${article.title} - 装样大师</title>`)
}
if (article.seo_keywords) {
finalHtml = finalHtml.replace(/<meta name="keywords" content="[^"]*"/, `<meta name="keywords" content="${article.seo_keywords}"`)
}
if (article.seo_description) {
finalHtml = finalHtml.replace(/<meta name="description" content="[^"]*"/, `<meta name="description" content="${article.seo_description}"`)
}
}
} else if (parsedUrl.pathname === '/article' && parsedUrl.query.category_id) {
const categoryId = parsedUrl.query.category_id
const res = await axios.get(`http://wechat.wenyitu.com/api/articles?category_id=${categoryId}&page=1&per_page=10`)
const data = res.data
if (data && data.items && data.items.length > 0 && data.items[0].category) {
const category = data.items[0].category
if (category.seo_keywords) {
finalHtml = finalHtml.replace(/<meta name="keywords" content="[^"]*"/, `<meta name="keywords" content="${category.seo_keywords}"`)
}
if (category.seo_description) {
finalHtml = finalHtml.replace(/<meta name="description" content="[^"]*"/, `<meta name="description" content="${category.seo_description}"`)
}
}
}
} catch (e) {
logger.error('获取文章详情用于SEO渲染失败: ' + String(e))
}
response.writeHead(httpOk, { 'Content-type': 'text/html;charset=utf-8' })
response.end(finalHtml)
logger.info(`${request.method} ${httpOk} ${request.url}`)
}
})
}
const matchType = async (request, response) => {
const isRouter = await matchRouter(request, response)
if (isRouter) {
return
}
let isFile = await matchFile(request, response)
if (isFile) {
return
}
let isProxy = matchProxy(request, response)
if (isProxy) {
return
}
await endIndex(request, response)
}
const httpService = async (request, response) => {
try {
await matchType(request, response)
} catch (e) {
response.writeHead(httpBadRequest, { 'Content-Type': 'application/json' })
response.end(
JSON.stringify({
code: -1,
message: String(e)
})
)
logger.info(`${request.method} ${httpBadRequest} ${request.url}`)
}
}
module.exports = {
httpService,
matchType,
matchRouter,
matchFile,
endIndex,
matchProxy,
}