feat:add domain config
This commit is contained in:
		
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -3,4 +3,6 @@ dist | |||||||
| coverage | coverage | ||||||
|  |  | ||||||
| .DS_Store | .DS_Store | ||||||
| upload | upload | ||||||
|  |  | ||||||
|  | app.config.json5 | ||||||
| @@ -1,8 +1,10 @@ | |||||||
| { | { | ||||||
|   port: 3005, |   port: 3005, | ||||||
|   api: { |   api: { | ||||||
|     host: 'codeflow.xiongxiao.me', // 后台代理 |     host: 'localhost:4000', // 后台代理 | ||||||
|  |     testHost: 'localhost:4000', | ||||||
|   }, |   }, | ||||||
|  |   allowedOrigins: ['localhost', 'xiongxiao.me', 'zxj.im'], | ||||||
|   domain: 'kevisual.xiongxiao.me', |   domain: 'kevisual.xiongxiao.me', | ||||||
|   resources: 'minio.xiongxiao.me/resources', |   resources: 'minio.xiongxiao.me/resources', | ||||||
| } | } | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ | |||||||
|   "main": "index.js", |   "main": "index.js", | ||||||
|   "type": "module", |   "type": "module", | ||||||
|   "scripts": { |   "scripts": { | ||||||
|     "dev": "nodemon --exec tsx src/index.ts", |     "dev": "cross-env NODE_ENV=development nodemon --exec tsx src/index.ts", | ||||||
|     "build": "rimraf dist && rollup -c", |     "build": "rimraf dist && rollup -c", | ||||||
|     "deploy": "rsync -avz dist/ light:~/apps/var-proxy/backend", |     "deploy": "rsync -avz dist/ light:~/apps/var-proxy/backend", | ||||||
|     "reload": "ssh light pm2 restart proxy" |     "reload": "ssh light pm2 restart proxy" | ||||||
| @@ -19,6 +19,7 @@ | |||||||
|     "@rollup/plugin-node-resolve": "^15.3.0", |     "@rollup/plugin-node-resolve": "^15.3.0", | ||||||
|     "@rollup/plugin-typescript": "^12.1.0", |     "@rollup/plugin-typescript": "^12.1.0", | ||||||
|     "@types/node": "^22.7.4", |     "@types/node": "^22.7.4", | ||||||
|  |     "cross-env": "^7.0.3", | ||||||
|     "nodemon": "^3.1.7", |     "nodemon": "^3.1.7", | ||||||
|     "rollup": "^4.24.0", |     "rollup": "^4.24.0", | ||||||
|     "ts-lib": "^0.0.5", |     "ts-lib": "^0.0.5", | ||||||
|   | |||||||
							
								
								
									
										56
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										56
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							| @@ -39,6 +39,9 @@ importers: | |||||||
|       '@types/node': |       '@types/node': | ||||||
|         specifier: ^22.7.4 |         specifier: ^22.7.4 | ||||||
|         version: 22.7.4 |         version: 22.7.4 | ||||||
|  |       cross-env: | ||||||
|  |         specifier: ^7.0.3 | ||||||
|  |         version: 7.0.3 | ||||||
|       nodemon: |       nodemon: | ||||||
|         specifier: ^3.1.7 |         specifier: ^3.1.7 | ||||||
|         version: 3.1.7 |         version: 3.1.7 | ||||||
| @@ -371,6 +374,15 @@ packages: | |||||||
|   concat-map@0.0.1: |   concat-map@0.0.1: | ||||||
|     resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} |     resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} | ||||||
|  |  | ||||||
|  |   cross-env@7.0.3: | ||||||
|  |     resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} | ||||||
|  |     engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} | ||||||
|  |     hasBin: true | ||||||
|  |  | ||||||
|  |   cross-spawn@7.0.3: | ||||||
|  |     resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} | ||||||
|  |     engines: {node: '>= 8'} | ||||||
|  |  | ||||||
|   debug@4.3.7: |   debug@4.3.7: | ||||||
|     resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} |     resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} | ||||||
|     engines: {node: '>=6.0'} |     engines: {node: '>=6.0'} | ||||||
| @@ -506,6 +518,9 @@ packages: | |||||||
|   is-reference@1.2.1: |   is-reference@1.2.1: | ||||||
|     resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} |     resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} | ||||||
|  |  | ||||||
|  |   isexe@2.0.0: | ||||||
|  |     resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} | ||||||
|  |  | ||||||
|   jest-worker@27.5.1: |   jest-worker@27.5.1: | ||||||
|     resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} |     resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} | ||||||
|     engines: {node: '>= 10.13.0'} |     engines: {node: '>= 10.13.0'} | ||||||
| @@ -575,6 +590,10 @@ packages: | |||||||
|     resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} |     resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} | ||||||
|     engines: {node: '>=0.10.0'} |     engines: {node: '>=0.10.0'} | ||||||
|  |  | ||||||
|  |   path-key@3.1.1: | ||||||
|  |     resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} | ||||||
|  |     engines: {node: '>=8'} | ||||||
|  |  | ||||||
|   path-parse@1.0.7: |   path-parse@1.0.7: | ||||||
|     resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} |     resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} | ||||||
|  |  | ||||||
| @@ -631,6 +650,14 @@ packages: | |||||||
|   serialize-javascript@6.0.2: |   serialize-javascript@6.0.2: | ||||||
|     resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} |     resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} | ||||||
|  |  | ||||||
|  |   shebang-command@2.0.0: | ||||||
|  |     resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} | ||||||
|  |     engines: {node: '>=8'} | ||||||
|  |  | ||||||
|  |   shebang-regex@3.0.0: | ||||||
|  |     resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} | ||||||
|  |     engines: {node: '>=8'} | ||||||
|  |  | ||||||
|   simple-update-notifier@2.0.0: |   simple-update-notifier@2.0.0: | ||||||
|     resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} |     resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} | ||||||
|     engines: {node: '>=10'} |     engines: {node: '>=10'} | ||||||
| @@ -749,6 +776,11 @@ packages: | |||||||
|       webpack-cli: |       webpack-cli: | ||||||
|         optional: true |         optional: true | ||||||
|  |  | ||||||
|  |   which@2.0.2: | ||||||
|  |     resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} | ||||||
|  |     engines: {node: '>= 8'} | ||||||
|  |     hasBin: true | ||||||
|  |  | ||||||
| snapshots: | snapshots: | ||||||
|  |  | ||||||
|   '@abearxiong/use-config@0.0.2': {} |   '@abearxiong/use-config@0.0.2': {} | ||||||
| @@ -1055,6 +1087,16 @@ snapshots: | |||||||
|  |  | ||||||
|   concat-map@0.0.1: {} |   concat-map@0.0.1: {} | ||||||
|  |  | ||||||
|  |   cross-env@7.0.3: | ||||||
|  |     dependencies: | ||||||
|  |       cross-spawn: 7.0.3 | ||||||
|  |  | ||||||
|  |   cross-spawn@7.0.3: | ||||||
|  |     dependencies: | ||||||
|  |       path-key: 3.1.1 | ||||||
|  |       shebang-command: 2.0.0 | ||||||
|  |       which: 2.0.2 | ||||||
|  |  | ||||||
|   debug@4.3.7(supports-color@5.5.0): |   debug@4.3.7(supports-color@5.5.0): | ||||||
|     dependencies: |     dependencies: | ||||||
|       ms: 2.1.3 |       ms: 2.1.3 | ||||||
| @@ -1164,6 +1206,8 @@ snapshots: | |||||||
|     dependencies: |     dependencies: | ||||||
|       '@types/estree': 1.0.6 |       '@types/estree': 1.0.6 | ||||||
|  |  | ||||||
|  |   isexe@2.0.0: {} | ||||||
|  |  | ||||||
|   jest-worker@27.5.1: |   jest-worker@27.5.1: | ||||||
|     dependencies: |     dependencies: | ||||||
|       '@types/node': 22.7.4 |       '@types/node': 22.7.4 | ||||||
| @@ -1226,6 +1270,8 @@ snapshots: | |||||||
|  |  | ||||||
|   normalize-path@3.0.0: {} |   normalize-path@3.0.0: {} | ||||||
|  |  | ||||||
|  |   path-key@3.1.1: {} | ||||||
|  |  | ||||||
|   path-parse@1.0.7: {} |   path-parse@1.0.7: {} | ||||||
|  |  | ||||||
|   picocolors@1.1.0: {} |   picocolors@1.1.0: {} | ||||||
| @@ -1292,6 +1338,12 @@ snapshots: | |||||||
|     dependencies: |     dependencies: | ||||||
|       randombytes: 2.1.0 |       randombytes: 2.1.0 | ||||||
|  |  | ||||||
|  |   shebang-command@2.0.0: | ||||||
|  |     dependencies: | ||||||
|  |       shebang-regex: 3.0.0 | ||||||
|  |  | ||||||
|  |   shebang-regex@3.0.0: {} | ||||||
|  |  | ||||||
|   simple-update-notifier@2.0.0: |   simple-update-notifier@2.0.0: | ||||||
|     dependencies: |     dependencies: | ||||||
|       semver: 7.6.3 |       semver: 7.6.3 | ||||||
| @@ -1411,3 +1463,7 @@ snapshots: | |||||||
|       - '@swc/core' |       - '@swc/core' | ||||||
|       - esbuild |       - esbuild | ||||||
|       - uglify-js |       - uglify-js | ||||||
|  |  | ||||||
|  |   which@2.0.2: | ||||||
|  |     dependencies: | ||||||
|  |       isexe: 2.0.0 | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ import path from 'path'; | |||||||
| export const getContentType = (filePath: string) => { | export const getContentType = (filePath: string) => { | ||||||
|   const extname = path.extname(filePath); |   const extname = path.extname(filePath); | ||||||
|   const contentType = { |   const contentType = { | ||||||
|  |     '.txt': 'text/plain', | ||||||
|     '.html': 'text/html', |     '.html': 'text/html', | ||||||
|     '.js': 'text/javascript', |     '.js': 'text/javascript', | ||||||
|     '.css': 'text/css', |     '.css': 'text/css', | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ import { pipeline } from 'stream'; | |||||||
| import { promisify } from 'util'; | import { promisify } from 'util'; | ||||||
| const pipelineAsync = promisify(pipeline); | const pipelineAsync = promisify(pipeline); | ||||||
|  |  | ||||||
| const { resources } = useConfig<{ resources: string }>(); | const { resources, api } = useConfig<{ resources: string; api: { host: string; testHost: string } }>(); | ||||||
| const fileStore = useFileStore('upload'); | const fileStore = useFileStore('upload'); | ||||||
|  |  | ||||||
| const demoData = { | const demoData = { | ||||||
| @@ -36,30 +36,6 @@ const demoData = { | |||||||
|     ], |     ], | ||||||
|   }, |   }, | ||||||
| }; | }; | ||||||
| const demoData2 = { |  | ||||||
|   user: 'root', |  | ||||||
|   key: 'codeflow', |  | ||||||
|   appType: 'web-single', // |  | ||||||
|   version: '0.0.1', |  | ||||||
|   domain: null, |  | ||||||
|   type: 'oss', // 是否使用oss |  | ||||||
|   data: { |  | ||||||
|     files: [ |  | ||||||
|       { |  | ||||||
|         name: 'index.html', |  | ||||||
|         path: 'root/codeflow/0.0.1/index.html', |  | ||||||
|       }, |  | ||||||
|       { |  | ||||||
|         name: 'assets/index-14y4J8dP.js', |  | ||||||
|         path: 'root/codeflow/0.0.1/assets/index-14y4J8dP.js', |  | ||||||
|       }, |  | ||||||
|       { |  | ||||||
|         name: 'assets/index-C-libw4a.css', |  | ||||||
|         path: 'root/codeflow/0.0.1/assets/index-C-libw4a.css', |  | ||||||
|       }, |  | ||||||
|     ], |  | ||||||
|   }, |  | ||||||
| }; |  | ||||||
| type UserAppOptions = { | type UserAppOptions = { | ||||||
|   user: string; |   user: string; | ||||||
|   app: string; |   app: string; | ||||||
| @@ -94,16 +70,89 @@ export class UserApp { | |||||||
|     const value = await redis.hget(key, appFileUrl); |     const value = await redis.hget(key, appFileUrl); | ||||||
|     return value; |     return value; | ||||||
|   } |   } | ||||||
|  |   static async getDomainApp(domain: string) { | ||||||
|  |     const key = 'domain:' + domain; | ||||||
|  |     const value = await redis.get(key); | ||||||
|  |     if (value) { | ||||||
|  |       const [_user, _app] = value.split(':'); | ||||||
|  |       return { | ||||||
|  |         user: _user, | ||||||
|  |         app: _app, | ||||||
|  |       }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // 获取域名对应的用户和应用 | ||||||
|  |     const isDev = process.env.NODE_ENV === 'development'; | ||||||
|  |     const fetchTestUrl = 'http://' + api.testHost + '/api/router'; | ||||||
|  |     const fetchUrl = 'http://' + api.host + '/api/router'; | ||||||
|  |     const fetchRes = await fetch(isDev ? fetchTestUrl : fetchUrl, { | ||||||
|  |       method: 'POST', | ||||||
|  |       headers: { | ||||||
|  |         'Content-Type': 'application/json', | ||||||
|  |       }, | ||||||
|  |       body: JSON.stringify({ | ||||||
|  |         path: 'app', | ||||||
|  |         key: 'getDomainApp', | ||||||
|  |         data: { | ||||||
|  |           domain, | ||||||
|  |         }, | ||||||
|  |       }), | ||||||
|  |     }).then((res) => res.json()); | ||||||
|  |     if (fetchRes?.code !== 200) { | ||||||
|  |       console.log('fetchRes is error', fetchRes); | ||||||
|  |       return null; | ||||||
|  |     } | ||||||
|  |     const fetchData = fetchRes.data; | ||||||
|  |     const data = { | ||||||
|  |       user: fetchData.user, | ||||||
|  |       app: fetchData.key, | ||||||
|  |     }; | ||||||
|  |     redis.set(key, data.user + ':' + data.app, 'EX', 60 * 60 * 24 * 7); // 24小时 | ||||||
|  |     return data; | ||||||
|  |   } | ||||||
|   async setCacheData() { |   async setCacheData() { | ||||||
|     const app = this.app; |     const app = this.app; | ||||||
|     const user = this.user; |     const user = this.user; | ||||||
|     const key = 'user:app:' + app + ':' + user; |     const key = 'user:app:' + app + ':' + user; | ||||||
|     // 如果demoData 不存在则返回 |     const isDev = process.env.NODE_ENV === 'development'; | ||||||
|     if (!demoData2) { |     const fetchTestUrl = 'http://' + api.testHost + '/api/router'; | ||||||
|  |     const fetchUrl = 'http://' + api.host + '/api/router'; | ||||||
|  |     const fetchRes = await fetch(isDev ? fetchTestUrl : fetchUrl, { | ||||||
|  |       method: 'POST', | ||||||
|  |       headers: { | ||||||
|  |         'Content-Type': 'application/json', | ||||||
|  |       }, | ||||||
|  |       body: JSON.stringify({ | ||||||
|  |         path: 'app', | ||||||
|  |         key: 'getApp', | ||||||
|  |         data: { | ||||||
|  |           user, | ||||||
|  |           key: app, | ||||||
|  |         }, | ||||||
|  |       }), | ||||||
|  |     }).then((res) => res.json()); | ||||||
|  |     if (fetchRes?.code !== 200) { | ||||||
|  |       console.log('fetchRes is error', fetchRes); | ||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
|     const value = await downloadUserAppFiles(user, app, demoData2); |     const fetchData = fetchRes.data; | ||||||
|     const valueIndexHtml = value.data.files.find((file) => file.name === 'index.html'); |     if (!fetchData.type) { | ||||||
|  |       // console.error('fetchData type is error', fetchData); | ||||||
|  |       // return false; | ||||||
|  |       fetchData.type = 'oss'; | ||||||
|  |     } | ||||||
|  |     const value = await downloadUserAppFiles(user, app, fetchData); | ||||||
|  |     if (value.data.files.length === 0) { | ||||||
|  |       console.error('root files length is zero', user, app); | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |     let valueIndexHtml = value.data.files.find((file) => file.name === 'index.html'); | ||||||
|  |     if (!valueIndexHtml) { | ||||||
|  |       valueIndexHtml = value.data.files.find((file) => file.name === 'index.js'); | ||||||
|  |       if (!valueIndexHtml) { | ||||||
|  |         valueIndexHtml = value.data.files[0]; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|     await redis.set(key, JSON.stringify(value)); |     await redis.set(key, JSON.stringify(value)); | ||||||
|     await redis.set('user:app:exist:' + app + ':' + user, valueIndexHtml.path, 'EX', 60 * 60 * 24 * 7); // 24小时 |     await redis.set('user:app:exist:' + app + ':' + user, valueIndexHtml.path, 'EX', 60 * 60 * 24 * 7); // 24小时 | ||||||
|     const files = value.data.files; |     const files = value.data.files; | ||||||
| @@ -140,9 +189,6 @@ export class UserApp { | |||||||
|     // 删除所有文件 |     // 删除所有文件 | ||||||
|     deleteUserAppFiles(user, app); |     deleteUserAppFiles(user, app); | ||||||
|   } |   } | ||||||
|   async getData() { |  | ||||||
|     return demoData; |  | ||||||
|   } |  | ||||||
|   async close() { |   async close() { | ||||||
|     // 关闭连接 |     // 关闭连接 | ||||||
|     await redis.quit(); |     await redis.quit(); | ||||||
|   | |||||||
| @@ -7,11 +7,12 @@ import fs from 'fs'; | |||||||
| import { useConfig } from '@abearxiong/use-config'; | import { useConfig } from '@abearxiong/use-config'; | ||||||
| import { redis } from './redis/redis.ts'; | import { redis } from './redis/redis.ts'; | ||||||
| import { getContentType } from './get-content-type.ts'; | import { getContentType } from './get-content-type.ts'; | ||||||
| const { api, domain } = useConfig<{ | const { api, domain, allowedOrigins } = useConfig<{ | ||||||
|   api: { |   api: { | ||||||
|     host: string; |     host: string; | ||||||
|   }; |   }; | ||||||
|   domain: string; |   domain: string; | ||||||
|  |   allowedOrigins: string[]; | ||||||
| }>(); | }>(); | ||||||
|  |  | ||||||
| const fileStore = useFileStore('upload'); | const fileStore = useFileStore('upload'); | ||||||
| @@ -19,6 +20,18 @@ console.log('filePath', fileStore); | |||||||
| const noProxyUrl = ['/', '/favicon.ico']; | const noProxyUrl = ['/', '/favicon.ico']; | ||||||
| export const handleRequest = async (req: http.IncomingMessage, res: http.ServerResponse) => { | export const handleRequest = async (req: http.IncomingMessage, res: http.ServerResponse) => { | ||||||
|   const dns = getDNS(req); |   const dns = getDNS(req); | ||||||
|  |   // 配置可以跨域 | ||||||
|  |   // 配置可以访问的域名 localhost, xiongxiao.me | ||||||
|  |   const _orings = allowedOrigins || []; | ||||||
|  |   const host = dns.hostName; | ||||||
|  |   if ( | ||||||
|  |     _orings.some((item) => { | ||||||
|  |       return host.includes(item); | ||||||
|  |     }) | ||||||
|  |   ) { | ||||||
|  |     res.setHeader('Access-Control-Allow-Origin', '*'); | ||||||
|  |   } | ||||||
|  |   res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); | ||||||
|  |  | ||||||
|   let user, app; |   let user, app; | ||||||
|   let domainApp = false; |   let domainApp = false; | ||||||
| @@ -33,21 +46,19 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR | |||||||
|     if (dns.hostName !== domain) { |     if (dns.hostName !== domain) { | ||||||
|       // redis获取域名对应的用户和应用 |       // redis获取域名对应的用户和应用 | ||||||
|       domainApp = true; |       domainApp = true; | ||||||
|       const key = 'domain:' + dns.hostName; |       const data = await UserApp.getDomainApp(dns.hostName); | ||||||
|       const value = await redis.get(key); |       if (!data) { | ||||||
|       if (!value) { |  | ||||||
|         res.writeHead(404, { 'Content-Type': 'text/plain' }); |         res.writeHead(404, { 'Content-Type': 'text/plain' }); | ||||||
|         res.write('Invalid domain\n'); |         res.write('Invalid domain\n'); | ||||||
|         return res.end(); |         return res.end(); | ||||||
|       } |       } | ||||||
|       const [_user, _app] = value.split(':'); |       if (!data.user || !data.app) { | ||||||
|       if (!_user || !_app) { |  | ||||||
|         res.writeHead(404, { 'Content-Type': 'text/plain' }); |         res.writeHead(404, { 'Content-Type': 'text/plain' }); | ||||||
|         res.write('Invalid domain, Config error\n'); |         res.write('Invalid domain config\n'); | ||||||
|         return res.end(); |         return res.end(); | ||||||
|       } |       } | ||||||
|       user = _user; |       user = data.user; | ||||||
|       app = _app; |       app = data.app; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   const url = req.url; |   const url = req.url; | ||||||
| @@ -145,8 +156,10 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR | |||||||
|   const appFile = await userApp.getFile(appFileUrl); |   const appFile = await userApp.getFile(appFileUrl); | ||||||
|   if (!appFile) { |   if (!appFile) { | ||||||
|     const [indexFilePath, etag] = indexFile.split('||'); |     const [indexFilePath, etag] = indexFile.split('||'); | ||||||
|  |     const contentType = getContentType(indexFilePath); | ||||||
|  |     const isHTML = contentType.includes('html'); | ||||||
|     // 不存在的文件,返回indexFile的文件 |     // 不存在的文件,返回indexFile的文件 | ||||||
|     res.writeHead(200, { 'Content-Type': 'text/html', 'Cache-Control': 'no-cache' }); |     res.writeHead(200, { 'Content-Type': contentType, 'Cache-Control': isHTML ? 'no-cache' : 'public, max-age=3600' }); | ||||||
|     const filePath = path.join(fileStore, indexFilePath); |     const filePath = path.join(fileStore, indexFilePath); | ||||||
|     const readStream = fs.createReadStream(filePath); |     const readStream = fs.createReadStream(filePath); | ||||||
|     readStream.pipe(res); |     readStream.pipe(res); | ||||||
| @@ -161,9 +174,10 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR | |||||||
|     } |     } | ||||||
|     const filePath = path.join(fileStore, appFilePath); |     const filePath = path.join(fileStore, appFilePath); | ||||||
|     let contentType = getContentType(filePath); |     let contentType = getContentType(filePath); | ||||||
|  |     const isHTML = contentType.includes('html'); | ||||||
|     res.writeHead(200, { |     res.writeHead(200, { | ||||||
|       'Content-Type': contentType, |       'Content-Type': contentType, | ||||||
|       'Cache-Control': 'public, max-age=3600', // 设置缓存时间为 1 小时 |       'Cache-Control': isHTML ? 'no-cache' : 'public, max-age=3600', // 设置缓存时间为 1 小时 | ||||||
|       ETag: eTag, |       ETag: eTag, | ||||||
|     }); |     }); | ||||||
|     const readStream = fs.createReadStream(filePath); |     const readStream = fs.createReadStream(filePath); | ||||||
|   | |||||||
| @@ -31,7 +31,8 @@ const clearData = async () => { | |||||||
| }; | }; | ||||||
|  |  | ||||||
| // clearData(); | // clearData(); | ||||||
| clearAllUserApp(); | // clearAllUserApp(); | ||||||
|  |  | ||||||
|  |  | ||||||
| const expireData = async () => { | const expireData = async () => { | ||||||
|   await redis.set('user:app:exist:' + 'codeflow:root', 'value', 'EX', 2); |   await redis.set('user:app:exist:' + 'codeflow:root', 'value', 'EX', 2); | ||||||
| @@ -39,3 +40,10 @@ const expireData = async () => { | |||||||
| }; | }; | ||||||
|  |  | ||||||
| // expireData(); | // expireData(); | ||||||
|  |  | ||||||
|  | const keysData = async () => { | ||||||
|  |   const keys = await redis.keys('user:app:exist:*'); | ||||||
|  |   console.log('keys', keys); | ||||||
|  |   process.exit(0); | ||||||
|  | } | ||||||
|  | keysData(); | ||||||
		Reference in New Issue
	
	Block a user