重构后端,完善获取资源/下载列表、博客列表接口

This commit is contained in:
2024-08-29 21:59:55 +08:00
parent 2a005b2e14
commit bc99fba385
18 changed files with 486 additions and 193 deletions

View File

View File

@@ -5,14 +5,15 @@
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
"start": "nodemon index.ts" "start": "ts-node src/index.ts"
}, },
"keywords": [], "keywords": [],
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"devDependencies": { "devDependencies": {
"@types/cors": "^2.8.17",
"@types/express": "^4.17.21",
"@types/node": "^20.12.12", "@types/node": "^20.12.12",
"nodemon": "^3.1.0",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"typescript": "^5.4.5" "typescript": "^5.4.5"
}, },

267
Server/pnpm-lock.yaml generated
View File

@@ -19,12 +19,15 @@ dependencies:
version: 3.9.7 version: 3.9.7
devDependencies: devDependencies:
'@types/cors':
specifier: ^2.8.17
version: 2.8.17
'@types/express':
specifier: ^4.17.21
version: 4.17.21
'@types/node': '@types/node':
specifier: ^20.12.12 specifier: ^20.12.12
version: 20.12.12 version: 20.12.12
nodemon:
specifier: ^3.1.0
version: 3.1.0
ts-node: ts-node:
specifier: ^10.9.2 specifier: ^10.9.2
version: 10.9.2(@types/node@20.12.12)(typescript@5.4.5) version: 10.9.2(@types/node@20.12.12)(typescript@5.4.5)
@@ -77,12 +80,80 @@ packages:
resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==}
dev: true dev: true
/@types/body-parser@1.19.5:
resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==}
dependencies:
'@types/connect': 3.4.38
'@types/node': 20.12.12
dev: true
/@types/connect@3.4.38:
resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
dependencies:
'@types/node': 20.12.12
dev: true
/@types/cors@2.8.17:
resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==}
dependencies:
'@types/node': 20.12.12
dev: true
/@types/express-serve-static-core@4.19.5:
resolution: {integrity: sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==}
dependencies:
'@types/node': 20.12.12
'@types/qs': 6.9.15
'@types/range-parser': 1.2.7
'@types/send': 0.17.4
dev: true
/@types/express@4.17.21:
resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==}
dependencies:
'@types/body-parser': 1.19.5
'@types/express-serve-static-core': 4.19.5
'@types/qs': 6.9.15
'@types/serve-static': 1.15.7
dev: true
/@types/http-errors@2.0.4:
resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==}
dev: true
/@types/mime@1.3.5:
resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==}
dev: true
/@types/node@20.12.12: /@types/node@20.12.12:
resolution: {integrity: sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==} resolution: {integrity: sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==}
dependencies: dependencies:
undici-types: 5.26.5 undici-types: 5.26.5
dev: true dev: true
/@types/qs@6.9.15:
resolution: {integrity: sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==}
dev: true
/@types/range-parser@1.2.7:
resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==}
dev: true
/@types/send@0.17.4:
resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==}
dependencies:
'@types/mime': 1.3.5
'@types/node': 20.12.12
dev: true
/@types/serve-static@1.15.7:
resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==}
dependencies:
'@types/http-errors': 2.0.4
'@types/node': 20.12.12
'@types/send': 0.17.4
dev: true
/accepts@1.3.8: /accepts@1.3.8:
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
@@ -102,14 +173,6 @@ packages:
hasBin: true hasBin: true
dev: true dev: true
/anymatch@3.1.3:
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
engines: {node: '>= 8'}
dependencies:
normalize-path: 3.0.0
picomatch: 2.3.1
dev: true
/arg@4.1.3: /arg@4.1.3:
resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
dev: true dev: true
@@ -118,15 +181,6 @@ packages:
resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==}
dev: false dev: false
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: true
/binary-extensions@2.3.0:
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
engines: {node: '>=8'}
dev: true
/body-parser@1.20.2: /body-parser@1.20.2:
resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==} resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==}
engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
@@ -147,20 +201,6 @@ packages:
- supports-color - supports-color
dev: false dev: false
/brace-expansion@1.1.11:
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
dependencies:
balanced-match: 1.0.2
concat-map: 0.0.1
dev: true
/braces@3.0.2:
resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
engines: {node: '>=8'}
dependencies:
fill-range: 7.0.1
dev: true
/bytes@3.1.2: /bytes@3.1.2:
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
@@ -177,30 +217,11 @@ packages:
set-function-length: 1.2.2 set-function-length: 1.2.2
dev: false dev: false
/chokidar@3.6.0:
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
engines: {node: '>= 8.10.0'}
dependencies:
anymatch: 3.1.3
braces: 3.0.2
glob-parent: 5.1.2
is-binary-path: 2.1.0
is-glob: 4.0.3
normalize-path: 3.0.0
readdirp: 3.6.0
optionalDependencies:
fsevents: 2.3.3
dev: true
/cluster-key-slot@1.1.2: /cluster-key-slot@1.1.2:
resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
dev: false dev: false
/concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
dev: true
/content-disposition@0.5.4: /content-disposition@0.5.4:
resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
@@ -245,7 +266,7 @@ packages:
ms: 2.0.0 ms: 2.0.0
dev: false dev: false
/debug@4.3.4(supports-color@5.5.0): /debug@4.3.4:
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
engines: {node: '>=6.0'} engines: {node: '>=6.0'}
peerDependencies: peerDependencies:
@@ -255,7 +276,7 @@ packages:
optional: true optional: true
dependencies: dependencies:
ms: 2.1.2 ms: 2.1.2
supports-color: 5.5.0 dev: false
/define-data-property@1.1.4: /define-data-property@1.1.4:
resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
@@ -355,13 +376,6 @@ packages:
- supports-color - supports-color
dev: false dev: false
/fill-range@7.0.1:
resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
engines: {node: '>=8'}
dependencies:
to-regex-range: 5.0.1
dev: true
/finalhandler@1.2.0: /finalhandler@1.2.0:
resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==} resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
@@ -387,14 +401,6 @@ packages:
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
dev: false dev: false
/fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
requiresBuild: true
dev: true
optional: true
/function-bind@1.1.2: /function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
dev: false dev: false
@@ -416,23 +422,12 @@ packages:
hasown: 2.0.2 hasown: 2.0.2
dev: false dev: false
/glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
dependencies:
is-glob: 4.0.3
dev: true
/gopd@1.0.1: /gopd@1.0.1:
resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
dependencies: dependencies:
get-intrinsic: 1.2.4 get-intrinsic: 1.2.4
dev: false dev: false
/has-flag@3.0.0:
resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
engines: {node: '>=4'}
/has-property-descriptors@1.0.2: /has-property-descriptors@1.0.2:
resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
dependencies: dependencies:
@@ -481,10 +476,6 @@ packages:
safer-buffer: 2.1.2 safer-buffer: 2.1.2
dev: false dev: false
/ignore-by-default@1.0.1:
resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==}
dev: true
/inherits@2.0.4: /inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
dev: false dev: false
@@ -495,7 +486,7 @@ packages:
dependencies: dependencies:
'@ioredis/commands': 1.2.0 '@ioredis/commands': 1.2.0
cluster-key-slot: 1.1.2 cluster-key-slot: 1.1.2
debug: 4.3.4(supports-color@5.5.0) debug: 4.3.4
denque: 2.1.0 denque: 2.1.0
lodash.defaults: 4.2.0 lodash.defaults: 4.2.0
lodash.isarguments: 3.1.0 lodash.isarguments: 3.1.0
@@ -511,30 +502,6 @@ packages:
engines: {node: '>= 0.10'} engines: {node: '>= 0.10'}
dev: false dev: false
/is-binary-path@2.1.0:
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
engines: {node: '>=8'}
dependencies:
binary-extensions: 2.3.0
dev: true
/is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
dev: true
/is-glob@4.0.3:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
dependencies:
is-extglob: 2.1.1
dev: true
/is-number@7.0.0:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
dev: true
/is-property@1.0.2: /is-property@1.0.2:
resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==}
dev: false dev: false
@@ -597,18 +564,13 @@ packages:
hasBin: true hasBin: true
dev: false dev: false
/minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
dependencies:
brace-expansion: 1.1.11
dev: true
/ms@2.0.0: /ms@2.0.0:
resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
dev: false dev: false
/ms@2.1.2: /ms@2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
dev: false
/ms@2.1.3: /ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
@@ -640,28 +602,6 @@ packages:
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
dev: false dev: false
/nodemon@3.1.0:
resolution: {integrity: sha512-xqlktYlDMCepBJd43ZQhjWwMw2obW/JRvkrLxq5RCNcuDDX1DbcPT+qT1IlIIdf+DhnWs90JpTMe+Y5KxOchvA==}
engines: {node: '>=10'}
hasBin: true
dependencies:
chokidar: 3.6.0
debug: 4.3.4(supports-color@5.5.0)
ignore-by-default: 1.0.1
minimatch: 3.1.2
pstree.remy: 1.1.8
semver: 7.6.2
simple-update-notifier: 2.0.0
supports-color: 5.5.0
touch: 3.1.1
undefsafe: 2.0.5
dev: true
/normalize-path@3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
dev: true
/object-assign@4.1.1: /object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
@@ -687,11 +627,6 @@ packages:
resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==}
dev: false dev: false
/picomatch@2.3.1:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
dev: true
/proxy-addr@2.0.7: /proxy-addr@2.0.7:
resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
engines: {node: '>= 0.10'} engines: {node: '>= 0.10'}
@@ -700,10 +635,6 @@ packages:
ipaddr.js: 1.9.1 ipaddr.js: 1.9.1
dev: false dev: false
/pstree.remy@1.1.8:
resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==}
dev: true
/qs@6.11.0: /qs@6.11.0:
resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==}
engines: {node: '>=0.6'} engines: {node: '>=0.6'}
@@ -726,13 +657,6 @@ packages:
unpipe: 1.0.0 unpipe: 1.0.0
dev: false dev: false
/readdirp@3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
dependencies:
picomatch: 2.3.1
dev: true
/redis-errors@1.2.0: /redis-errors@1.2.0:
resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==}
engines: {node: '>=4'} engines: {node: '>=4'}
@@ -753,12 +677,6 @@ packages:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
dev: false dev: false
/semver@7.6.2:
resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==}
engines: {node: '>=10'}
hasBin: true
dev: true
/send@0.18.0: /send@0.18.0:
resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==}
engines: {node: '>= 0.8.0'} engines: {node: '>= 0.8.0'}
@@ -822,13 +740,6 @@ packages:
object-inspect: 1.13.1 object-inspect: 1.13.1
dev: false dev: false
/simple-update-notifier@2.0.0:
resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==}
engines: {node: '>=10'}
dependencies:
semver: 7.6.2
dev: true
/sqlstring@2.3.3: /sqlstring@2.3.3:
resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==}
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
@@ -843,29 +754,11 @@ packages:
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
dev: false dev: false
/supports-color@5.5.0:
resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
engines: {node: '>=4'}
dependencies:
has-flag: 3.0.0
/to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
dependencies:
is-number: 7.0.0
dev: true
/toidentifier@1.0.1: /toidentifier@1.0.1:
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
engines: {node: '>=0.6'} engines: {node: '>=0.6'}
dev: false dev: false
/touch@3.1.1:
resolution: {integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==}
hasBin: true
dev: true
/ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5): /ts-node@10.9.2(@types/node@20.12.12)(typescript@5.4.5):
resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==}
hasBin: true hasBin: true
@@ -911,10 +804,6 @@ packages:
hasBin: true hasBin: true
dev: true dev: true
/undefsafe@2.0.5:
resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==}
dev: true
/undici-types@5.26.5: /undici-types@5.26.5:
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
dev: true dev: true

View File

@@ -0,0 +1,22 @@
import { API } from "../Plugs/API/API";
import ServerStdResponse from "../ServerStdResponse";
import MySQLConnection from '../Plugs/MySQLConnection'
// 获取博客列表
class GetBlogList extends API {
constructor() {
super('GET', '/blogList');
}
private defaultAccessLevel = 6;
public async onRequset(data: any, res: any) {
let blogListRes = await MySQLConnection.execute('SELECT uuid, title, description, publish_time from blog WHERE access_level > ? ORDER BY publish_time DESC',[this.defaultAccessLevel]);
if(!blogListRes){
this.logger.error('查询时数据库发生错误');
return res.json(ServerStdResponse.SERVER_ERROR);
}
return res.json({...ServerStdResponse.OK, data: blogListRes});
}
}
export default GetBlogList;

View File

@@ -0,0 +1,29 @@
import { API } from "../Plugs/API/API";
import ServerStdResponse from "../ServerStdResponse";
import MySQLConnection from '../Plugs/MySQLConnection'
// 获取资源列表
class GetResourceList extends API {
constructor() {
super('GET', '/resourceList');
}
private typeList = ['resource', 'download']
public async onRequset(data: any, res: any) {
let { type } = data;
if(!type){
return res.json(ServerStdResponse.PARAMS_MISSING);
}
if(!this.typeList.includes(type)){
return res.json(ServerStdResponse.INVALID_PARAMS);
}
let resourceListRes = await MySQLConnection.execute('SELECT * from resource WHERE type = ? ORDER BY recommand ASC',[type]);
if(!resourceListRes){
this.logger.error('查询时数据库发生错误');
return res.json(ServerStdResponse.SERVER_ERROR);
}
return res.json({...ServerStdResponse.OK, data: resourceListRes});
}
}
export default GetResourceList;

View File

@@ -0,0 +1,16 @@
import { API } from "../Plugs/API/API";
import ServerStdResponse from "../ServerStdResponse";
import MySQLConnection from '../Plugs/MySQLConnection'
// 测试接口
class GetTest extends API {
constructor() {
super('GET', '/test');
}
public async onRequset(data: any, res: any) {
res.json(ServerStdResponse.OK);
}
}
export default GetTest;

View File

@@ -0,0 +1,16 @@
import Logger from "../Logger";
abstract class API {
protected logger: Logger;
public middlewareFunc: Function[] = [];
constructor(public method: string, public uri: string, ...func: any) {
this.logger = new Logger('API][' + method + '][' + uri);
this.middlewareFunc.push(...func);
}
// to override
public abstract onRequset(data: any, res: any): void;
}
export { API };

View File

@@ -0,0 +1,53 @@
import express, { NextFunction, Request, Response } from "express";
import cors from "cors";
import Logger from "../Logger";
import { API } from "./API";
import ServerStdResponse from "../../ServerStdResponse";
class APILoader {
private app = express();
private logger = new Logger('APILoader');
constructor(private port?: number) {
this.logger.info('API服务加载中...');
this.app.use(express.json({ limit: '50mb' }));
this.app.use(express.urlencoded({ extended: true }));
this.app.use(cors({
origin: ['http://localhost:5173', 'http://note.ctbu.net.cn', 'http://124.223.5.195:23501'],
methods: ['GET', 'POST'],
allowedHeaders: ['Content-Type', 'Authorization', 'Access-Control-Allow-Origin', ''],
}));
}
add(api: { new(): API }) {
const instance = new api();
for (let func of instance.middlewareFunc) {
this.app[instance.method.toLowerCase() as keyof express.Application](instance.uri, (req: Request, res: Response, next: NextFunction) => {
func(req, res, next);
});
this.logger.info(`[${instance.method}][${instance.uri}] 已启用中间件[${func.name}]`);
}
this.app[instance.method.toLowerCase() as keyof express.Application](instance.uri, (req: Request, res: Response) => {
let ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress || req.ip;
this.logger.info(`[${instance.method}][${instance.uri}] 被请求[${(ip as string).replace('::ffff:', '')}]`);
const data = Object.assign({}, req.query, req.body);
instance.onRequset(data, res);
});
this.logger.info(`[${instance.method}][${instance.uri}] 加载成功`);
}
start(port?: number) {
if (this.port == undefined && port == undefined)
throw new Error('未指定API端口')
this.app.use((req: Request, res: Response) => {
this.logger.info(`[${req.method}][${req.url.split('?')[0]}] 该API不存在`);
res.json(ServerStdResponse.API_NOT_FOUND)
})
this.app.listen(port || this.port, () => {
this.logger.info(`已全部加载完成API服务开放在端口${port || this.port}`);
});
}
}
export {
APILoader,
}

View File

@@ -0,0 +1,40 @@
class Logger {
constructor(private namespace: string) {
}
private getTime(): string {
return new Date().toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' });
}
public info(info: string, ...args: any): void {
args = args.map((arg: any) => {
if (typeof arg === 'object') {
return JSON.stringify(arg);
}
return arg;
})
console.log(`[${this.getTime()}][INFO][${this.namespace}]${info[0] == '[' ? '' : ' '}${info} ` + args.join(' '));
}
public warn(info: string, ...args: any): void {
args = args.map((arg: any) => {
if (typeof arg === 'object') {
return JSON.stringify(arg);
}
return arg;
})
console.log(`[${this.getTime()}][WARN][${this.namespace}]${info[0] == '[' ? '' : ' '}${info} ` + args.join(' '));
}
public error(info: string, ...args: any): void {
args = args.map((arg: any) => {
if (typeof arg === 'object') {
return JSON.stringify(arg);
}
return arg;
})
console.log(`[${this.getTime()}][ERROR][${this.namespace}]${info[0] == '[' ? '' : ' '}${info} ` + args.join(' '));
}
}
export default Logger;

View File

@@ -0,0 +1,17 @@
import { Request, Response, NextFunction } from "express";
import config from "../../config";
import ServerStdResponse from "../../ServerStdResponse";
import Logger from "../Logger";
const logger = new Logger("Auth");
const Auth = (req: Request, res: Response, next: NextFunction) => {
let token = req.headers.authorization;
if (token === config.authToken || token == config.adminToken) {
next();
} else {
let ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress || req.ip;
logger.info(`API[${req.method}][${req.url.split('?')[0]}] 请求鉴权不通过[${token}][${ip}]`);
res.json(ServerStdResponse.AUTH_ERROR);
}
}
export default Auth;

View File

@@ -0,0 +1,17 @@
import { Request, Response, NextFunction } from "express";
import config from "../../config";
import ServerStdResponse from "../../ServerStdResponse";
import Logger from "../Logger";
const logger = new Logger("AuthAdmin");
const AuthAdmin = (req: Request, res: Response, next: NextFunction) => {
let token = req.headers.authorization;
if (token === config.adminToken) {
next();
} else {
let ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress || req.ip;
logger.info(`API[${req.method}][${req.url.split('?')[0]}] 请求鉴权不通过[${token}][${ip}]`);
res.json(ServerStdResponse.AUTH_ERROR);
}
}
export default AuthAdmin;

View File

@@ -0,0 +1,9 @@
import { Request, Response, NextFunction } from "express";
import Logger from "../Logger";
const logger = new Logger("Unbind");
const Unbind = (req: Request, res: Response, next: NextFunction) => {
let ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress || req.ip;
logger.info(`API[${req.method}][${req.url.split('?')[0]}] 请求了未绑定的接口[${ip}]`);
}
export default Unbind;

View File

@@ -0,0 +1,77 @@
// MYSQL数据库连接池
// 版本v0.1
import mysql from "mysql2/promise";
import Logger from "./Logger";
import config from "../config";
class MySQLConnectPool {
private pool: any;
private logger = new Logger('MySQLConnection');
constructor() {
this.pool = this.createConnectPool();
this.logger.info("[MySQL] 数据库连接池已创建")
setTimeout(async () => {
let res = await this.testConnection();
if (res)
this.logger.info("[MySQL] 数据库测试成功")
else
this.logger.error("[MySQL] 数据库测试失败")
}, 10);
}
// 内部函数,无需手动调用
createConnectPool() {
return mysql.createPool({
host: config.mysql.host,
database: config.mysql.database,
user: config.mysql.user,
password: config.mysql.password,
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
})
}
// 内部函数,无需手动调用
async testConnection() {
try {
let res = await this.execute("SELECT 1 + 1 As result");
if (res[0].result == 2)
return 1;
else
return 0;
} catch (error) {
this.logger.error(`[MySQL] 数据库测试发生了错误:` + error);
return 0;
}
}
// 执行SQL语句
async execute(sql: string, values?: any[], database?: string) {
let connection: any;
try {
connection = await this.pool.getConnection();
// 如果指定了数据库,则更改当前连接的数据库
if (database) {
await connection.changeUser({ database });
}
let [rows, fields] = await connection.execute(sql, values);
return rows;
} catch (error) {
this.logger.error("[MySQL] 数据库发生错误:" + error, '\n##', sql, '\n##', JSON.stringify(values));
return undefined;
} finally {
if (database)
await connection.changeUser({ database: config.mysql.database });// 恢复默认数据库
if (connection)
connection.release();
}
}
}
let MySQLConnection = new MySQLConnectPool();
export default MySQLConnection;

View File

@@ -0,0 +1,31 @@
import Logger from "../Plugs/Logger";
import { APILoader } from "../Plugs/API/APILoader";
import config from "../config";
import GetTest from "../APIs/GetTest";
import GetResourceList from "../APIs/GetResourceList";
import GetBlogList from "../APIs/GetBlogList";
class Server {
private logger = new Logger('Server');
public static instance: Server;
private apiLoader = new APILoader();
constructor() {
Server.instance = this;
}
public async start() {
// 加载前台API
this.apiLoader.add(GetTest);
this.apiLoader.add(GetResourceList);
this.apiLoader.add(GetBlogList);
this.apiLoader.start(config.apiPort);
}
}
let _Server = new Server();
export {
_Server as server,
}

View File

@@ -0,0 +1,52 @@
const ServerStdResponse = {
OK: {
code: 0,
message: 'OK'
},
PARAMS_MISSING: {
code: -1,
message: 'Parameters missing'
},
INVALID_PARAMS: {
code: -2,
message: 'Invalid parameters'
},
INVALID_TOKEN: {
code: -3,
message: 'Invalid token'
},
SERVER_ERROR: {
code: -4,
message: 'Server error'
},
API_NOT_FOUND: {
code: -5,
message: 'API not found'
},
AUTH_ERROR: {
code: -6,
message: 'Authentication error'
},
IDENTIFY_FAILED: {
code: -7,
message: 'Identify failed'
},
GOODS: {
NOTFOUND: {
code: -4001,
message: 'Goods not found'
}
},
ORDER: {
NOTFOUND: {
code: -5001,
message: 'Order not found'
},
ALREADY_CANCEL: {
code: -5002,
message: 'Order already canceled'
}
}
} as const;
export default ServerStdResponse;

15
Server/src/config.ts Normal file
View File

@@ -0,0 +1,15 @@
const config = {
mysql: {
host: 'localhost',
// host:'server.tonesc.cn',
database: 'tonecn',
user: 'root',
password: 'Shi15023847146'
// password: '245565'
},
authToken: '17e50223f4a545ec9e36ebf08e2f71bb',
adminToken: '3a6f71412f9e48b9bbbd056aa7eb5467',
apiPort: 23500,
} as const;
export default config;

11
Server/src/index.ts Normal file
View File

@@ -0,0 +1,11 @@
import Logger from "./Plugs/Logger";
let logger = new Logger("Server");
logger.info('服务正启动...');
import { server } from "./Server/Server";
async function main() {
server.start();
}
main().catch((err) => {
logger.error(err);
});

View File

@@ -7,8 +7,6 @@
"baseUrl": ".", "baseUrl": ".",
"paths": { "paths": {
"@/*": ["src/*"], "@/*": ["src/*"],
"@plugs/*": ["plugs/*"],
"@apis/*": ["apis/*"]
} }
} }
} }