Node.js+Express.js+TS實(shí)現(xiàn)簡(jiǎn)單圖床腳本
代碼實(shí)現(xiàn)
我將最新源碼放在了MoMeak9/img-service: 簡(jiǎn)單圖床腳本,但是這個(gè)是最終版本,添加了很多新的在后續(xù)文章才提到的功能,而本文的完整代碼我放在了文末,請(qǐng)客官自行取用。
首先,我們需要安裝一些依賴包,包括 express、multer 和 dotenv。express 是一個(gè)流行的 Node.js Web 框架,提供了基本的路由和中間件功能。multer 是一個(gè)用于處理 multipart/form-data 類型的請(qǐng)求體的中間件,可以方便地獲取上傳的文件。fs 是 Node.js 的內(nèi)置模塊,用于操作文件系統(tǒng)。path 也是 Node.js 的內(nèi)置模塊,用于處理文件路徑。dotenv 是一個(gè)用于加載環(huán)境變量的模塊,可以讓我們將一些敏感或配置信息存放在 .env 文件中,而不用暴露在代碼里。
我們可以使用 npm 或 yarn 來(lái)安裝這些依賴包:
npm install express multer fs path dotenv # or yarn add express multer fs path dotenv
然后,我們需要在項(xiàng)目根目錄下創(chuàng)建一個(gè) .env 文件,用來(lái)存放一些配置信息,比如服務(wù)器端口號(hào)、圖片存儲(chǔ)路徑和訪問域名等。例如:
PORT=8899 BASEURL=https://fs.lwmc.net
接下來(lái),我們需要在項(xiàng)目根目錄下創(chuàng)建一個(gè) src 文件夾,用來(lái)存放 TypeScript 源碼文件。在 src 文件夾下,我們創(chuàng)建一個(gè) index.ts 文件,作為入口文件。在 index.ts 文件中,我們首先需要導(dǎo)入一些模塊:
import express, {NextFunction, Request, Response} from 'express'; import multer from 'multer'; import fs from 'fs'; import path from 'path'; import dotenv from 'dotenv';
你也看出來(lái)了,我們還需要添加一些類型輔助
npm install @types/express @types/multer @types/node -D # or yarn add @types/express @types/multer @types/node -D
跨域配置(上傳和靜態(tài)文件跨域訪問能力)
// 允許跨域請(qǐng)求 app.use((req: Request, res: Response, next) => { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Methods', 'GET, POST'); res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With'); next(); });
路由
應(yīng)該包含有靜態(tài)資源路由和上傳路由:
靜態(tài)資源路由開放對(duì)/uploads
路徑下資源的訪問
// 靜態(tài)文件路由 app.use('/uploads', express.static(path.resolve(__dirname, '../uploads')));
上傳路由開放對(duì)/upload
POST方法的訪問:
upload.single('file')
是一個(gè) multer 中間件,表示只允許上傳一個(gè)文件,并且上傳的文件參數(shù)名是 'file'。(req: Request, res: Response) => { ... }
是路由處理函數(shù),當(dāng)客戶端向 '/upload' 路徑發(fā)送 POST 請(qǐng)求時(shí),會(huì)執(zhí)行這個(gè)函數(shù)。const file = req.file;
表示從請(qǐng)求中獲取上傳的文件。if (!file) { ... }
表示如果沒有上傳文件,返回一個(gè) 400 錯(cuò)誤響應(yīng)。res.send({ ... })
表示向客戶端發(fā)送一個(gè) JSON 響應(yīng),包含上傳文件的信息,包括文件名、原始文件名、文件類型、文件大小和文件的訪問路徑。其中文件訪問路徑是通過(guò)拼接服務(wù)器地址和文件路徑得到的。
// 上傳文件路由 app.post('/upload', upload.single('file'), (req: Request, res: Response) => { const file = req.file; if (!file) { res.status(400).send('Please upload a file.'); return; } // 返回文件信息 res.send({ filename: file.filename, originalname: file.originalname, mimetype: file.mimetype, size: file.size, path: `http://localhost:3000/${commonPath}/${file.filename}`, }); // 復(fù)原公共路徑 commonPath = 'uploads/' });
multer 配置
代碼使用了 multer 中間件來(lái)處理上傳文件的請(qǐng)求。Multer 是一個(gè) node.js 中間件,用于處理文件上傳,支持多文件上傳,可以設(shè)置文件大小、文件類型和保存路徑等。
以下是對(duì)代碼配置項(xiàng)的解釋:
dest
屬性指定上傳文件的保存目錄,這里設(shè)置為 'uploads/' 目錄下。如果目錄不存在,則會(huì)自動(dòng)創(chuàng)建。limits
屬性設(shè)置上傳文件的限制,這里限制文件大小為 10MB。fileFilter
屬性指定上傳文件的類型,這里限制只能上傳 image/png、image/jpeg、image/gif、image/webp、image/svg+xml 這些類型的文件。如果文件類型不在指定的類型列表中,則會(huì)觸發(fā)錯(cuò)誤。storage
屬性指定上傳文件的存儲(chǔ)方式,這里使用了 diskStorage 存儲(chǔ)方式。在存儲(chǔ)文件時(shí),會(huì)根據(jù)上傳時(shí)間按年月日來(lái)創(chuàng)建文件夾,并將文件存儲(chǔ)在對(duì)應(yīng)的文件夾下。filename
方法指定上傳文件的命名規(guī)則,這里使用時(shí)間戳加原始文件名的方式來(lái)命名文件。
// 上傳文件的中間件 const upload = multer({ dest: 'uploads/', limits: { fileSize: 1024 * 1024 * 10, // 限制文件大小為10M }, fileFilter: (req, file, cb) => { // 限制文件類型 const allowedTypes = ['image/png', 'image/jpeg', 'image/gif', 'image/webp', 'image/svg+xml']; if (!allowedTypes.includes(file.mimetype)) { cb(new Error('Invalid file type.')); return; } cb(null, true); }, storage: multer.diskStorage({ destination: (req, file, cb) => { if (!fs.existsSync('uploads/')) { fs.mkdirSync('uploads/'); } // 獲取日期 const date = new Date(); const year = date.getFullYear(); const month = date.getMonth() + 1; const day = date.getDate(); commonPath = path.join(commonPath, year.toString()); if (!fs.existsSync(path.join(commonPath))) { fs.mkdirSync(path.join(commonPath)); } commonPath = path.join(commonPath, month.toString().padStart(2, '0')); if (!fs.existsSync(path.join(commonPath))) { fs.mkdirSync(path.join(commonPath)); } // 拼接路徑 cb(null, commonPath); }, filename: (req, file, cb) => { cb(null, `${Date.now()}${file.originalname}`); }, }), });
完整代碼:
import express, {Request, Response} from 'express'; import multer from 'multer'; import fs from 'fs'; import path from 'path'; const app = express(); // 公共路徑 let commonPath = 'uploads/'; // 上傳文件的中間件 const upload = multer({ dest: 'uploads/', limits: { fileSize: 1024 * 1024 * 10, // 限制文件大小為10M }, fileFilter: (req, file, cb) => { // 限制文件類型 const allowedTypes = ['image/png', 'image/jpeg', 'image/gif', 'image/webp', 'image/svg+xml']; if (!allowedTypes.includes(file.mimetype)) { cb(new Error('Invalid file type.')); return; } cb(null, true); }, storage: multer.diskStorage({ destination: (req, file, cb) => { if (!fs.existsSync('uploads/')) { fs.mkdirSync('uploads/'); } // 獲取日期 const date = new Date(); const year = date.getFullYear(); const month = date.getMonth() + 1; const day = date.getDate(); commonPath = path.join(commonPath, year.toString()); if (!fs.existsSync(path.join(commonPath))) { fs.mkdirSync(path.join(commonPath)); } commonPath = path.join(commonPath, month.toString().padStart(2, '0')); if (!fs.existsSync(path.join(commonPath))) { fs.mkdirSync(path.join(commonPath)); } // 拼接路徑 cb(null, commonPath); }, filename: (req, file, cb) => { cb(null, `${Date.now()}${file.originalname}`); }, }), }); // 允許跨域請(qǐng)求 app.use((req: Request, res: Response, next) => { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Methods', 'GET, POST'); res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With'); next(); }); // 靜態(tài)文件路由 app.use('/uploads', express.static(path.resolve(__dirname, '../uploads'))); // 上傳文件路由 app.post('/upload', upload.single('file'), (req: Request, res: Response) => { const file = req.file; if (!file) { res.status(400).send('Please upload a file.'); return; } // 返回文件信息 res.send({ filename: file.filename, originalname: file.originalname, mimetype: file.mimetype, size: file.size, path: `http://localhost:3000/${commonPath}/${file.filename}`, }); commonPath = 'uploads/' }); // 啟動(dòng)服務(wù)器 const port = process.env.PORT || 3000; app.listen(port, () => { console.log(`server started at http://localhost:${port}`); });
以上就是Node.js+Express.js+TS實(shí)現(xiàn)簡(jiǎn)單圖床腳本的詳細(xì)內(nèi)容,更多關(guān)于Node.js Express.js TS圖床腳本的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
npm?install編譯時(shí)報(bào)"Cannot?read?properties?of?null?(r
這篇文章主要給大家介紹了關(guān)于npm?install編譯時(shí)報(bào)“Cannot?read?properties?of?null?(reading?‘pickAlgorithm‘)“錯(cuò)誤的解決辦法,文中將解決方法介紹的非常詳細(xì),需要的朋友可以參考下2022-07-07Nodejs腳本快速導(dǎo)出MySQL數(shù)據(jù)庫(kù)數(shù)據(jù)
在數(shù)據(jù)庫(kù)管理和數(shù)據(jù)遷移的過(guò)程中,常常需要將數(shù)據(jù)庫(kù)中的表數(shù)據(jù)和結(jié)構(gòu)進(jìn)行導(dǎo)出,本文將使用Node.js編寫一個(gè)腳本實(shí)現(xiàn)快速?gòu)腗ySQL數(shù)據(jù)庫(kù)中導(dǎo)出所有表的數(shù)據(jù)和結(jié)構(gòu),并保存為單獨(dú)的SQL文件,需要的可以參考下2024-10-10koa-passport實(shí)現(xiàn)本地驗(yàn)證的方法示例
這篇文章主要介紹了koa-passport實(shí)現(xiàn)本地驗(yàn)證的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02Node.js實(shí)用代碼段之獲取Buffer對(duì)象字節(jié)長(zhǎng)度
這篇文章主要介紹了Node.js實(shí)用代碼段之獲取Buffer對(duì)象字節(jié)長(zhǎng)度,需要的朋友可以參考下2016-03-03nodejs創(chuàng)建簡(jiǎn)易web服務(wù)器與文件讀寫的實(shí)例
下面小編就為大家?guī)?lái)一篇node js系列課程-創(chuàng)建簡(jiǎn)易web服務(wù)器與文件讀寫的實(shí)例。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-09-09Node.js中使用Log.io在瀏覽器中實(shí)時(shí)監(jiān)控日志(等同tail -f命令)
這篇文章主要介紹了Node.js中使用Log.io在瀏覽器中實(shí)時(shí)監(jiān)控日志,Log.io等同于tail -f命令,但更強(qiáng)大,需要的朋友可以參考下2014-09-09Nodejs為什么選擇javascript為載體語(yǔ)言
準(zhǔn)備寫一個(gè)NodeJS方面的系列文章,由淺入深,循序漸進(jìn),秉承的理念是重思想,多實(shí)踐,勤能補(bǔ)拙,貴在堅(jiān)持。本文首先來(lái)點(diǎn)基礎(chǔ)知識(shí)的開篇吧。2015-01-01