Follow the previous article: File upload server side complete code
const Koa = require('koa');
const Router = require('koa-router');
const koastatic = require('koa-static');
const fs = require('fs');
const formidable = require('formidable');
const multiparty = require('multiparty');
const SparkMD5 = require('spark-md5');
const path = require('path');
const app = new Koa();
let router = new Router();
// Middleware: set to allow cross-domain
app.use(async (ctx, next) => {
ctx.set('Access-Control-Allow-Origin'.The '*');
// Handle the OPTIONS request
ctx.request.methods === 'OPTIONS' ? ctx.body = 'Request test successful' : await next();
});
const host = '127.0.0.1',
port = 3000;
const HOSTNAME = `${host}:${port}`;
const SERVER_PATH = `${__dirname}/upload`;
app.listen(port, function () {
console.log('= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =');
console.log(`The server started at port: ${port}, you can access it by ${HOSTNAME}`);
console.log('= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =');
});
// Define the delay function
const delay = function delay(interval) {
typeofinterval ! = ='number' ? interval = 1000 : null;
return new Promise((resolve, reject) = > {
setTimeout(function () {
resolve();
}, interval);
});
}
// Check whether the file already exists
const exists = function exists(path) {
return new Promise((resolve, reject) = > {
fs.access(path, fs.constants.F_OK, err= > {
if (err) {
resolve(false);
return;
}
resolve(true);
});
});
}
// Use the Multiparty plug-in to parse the form-data format from the front end and upload it to the server
const multipartyUpload = function multipartyUpload(req, autoUpload) {
let config = {
maxFieldsSize: 200 * 1024 * 1024
}
if (autoUpload) config.uploadDir = SERVER_PATH;
return new Promise((resolve, reject) = > {
new multiparty.Form(config).parse(req, (err, fields, files) = > {
if (err) {
reject(err);
return;
}
resolve({
fields,
files
});
});
});
}
// Write the incoming file data to the server
// Data in form-data format will be written as a stream
// If the data is in BASE64 format, the content is written directly
const writeFile = function writeFile(serverPath, file, isStream) {
return new Promise((resolve, reject) = > {
if (isStream) {
try {
let readStream = fs.createReadStream(file.path);
let writeStream = fs.createWriteStream(serverPath);
readStream.pipe(writeStream);
readStream.on('end'.() = > {
resolve({
result: true.message: 'Upload successful! '
});
fs.unlinkSync(file.path);
});
} catch (err) {
resolve({
result: false.message: err
})
}
} else {
fs.writeFile(serverPath, file, err= > {
if (err) {
resolve({
result: false.message: err
})
return;
}
resolve({
result: true.message: 'Upload successful! '}); }); }}); }// Upload a single form-data file and use the third-party plug-in Multipary to parse and upload it
router.post('/upload_single_file'.async (ctx, next) => {
try {
let {
files
} = await multipartyUpload(ctx.req, true);
let file = (files && files.file.length) ? files.file[0] : {};
ctx.body = {
code: 0.message: 'File uploaded successfully'.originalFilename: file.originalFilename,
serverPath: file.path.replace(__dirname, HOSTNAME)
}
} catch (err) {
ctx.body = {
code: 1.message: 'File upload failed'}}});// Upload a single file (form-data). Use a third-party plug-in to parse the file but not directly upload it. Instead, rename the file and upload it separately
router.post('/upload_single_formdata_rename'.async (ctx, next) => {
try {
let {
files,
fields
} = await multipartyUpload(ctx.req, false);
let file = (files && files.file.length) ? files.file[0] : {};
let filename = (fields && fields.filename.length) ? fields.filename[0] : ' ';
const filePath = `${SERVER_PATH}/${filename}`;
let isExist = await exists(filePath);
if (isExist) {
ctx.body = {
code: 0.message: 'File already exists'.originalFilename: filename,
serverPath: file.path.replace(__dirname, HOSTNAME)
}
return;
}
let obj = await writeFile(filePath, file, true);
if (obj.result) {
ctx.body = {
code: 0.message: 'File uploaded successfully'.originalFilename: filename,
serverPath: file.path.replace(__dirname, HOSTNAME)
}
} else {
ctx.body = {
code: 0.message: 'File upload failed'}}}catch (ex) {
ctx.body = {
code: 0.message: ex
}
}
});
// Parse post request parameters, content-type = application/x-www-form-urlencoded or application/josn
const parsePostParams = function parsePostParams(req) {
return new Promise((resolve, reject) = > {
let form = new formidable.IncomingForm();
form.parse(req, (err, fields) = > {
if (err) {
reject(err);
return;
}
resolve(fields);
});
});
}
//BASE64 upload. This method can only be used to upload small images. It is not recommended to use this method to upload large images, which will cause program jam
router.post('/upload_base64'.async (ctx, next) => {
try {
let {
file,
filename
} = await parsePostParams(ctx.req);
file = decodeURIComponent(file);
const suffix = /\.([0-9a-zA-Z]+)$/.exec(filename)[1];
let spark = new SparkMD5.ArrayBuffer();
file = file.replace(/^data:image\/\w+; base64,/."");
file = Buffer.from(file, 'base64');
spark.append(file);
let filepath = `${SERVER_PATH}/${spark.end()}.${suffix}`;
await delay();
const isExists = await exists(filepath);
if (isExists) {
ctx.body = {
code: 0.message: 'File already exists'.originalFilename: filename,
serverPath: file.path.replace(__dirname, HOSTNAME)
}
return;
}
let obj = await writeFile(filepath, file, false);
if (obj.result) {
ctx.body = {
code: 0.message: 'File uploaded successfully'.originalFilename: filename,
serverPath: filepath.replace(__dirname, HOSTNAME)
}
} else {
ctx.body = {
code: 0.message: 'File upload failed'}}}catch (err) {
console.log(err);
ctx.body = {
code: 0.message: err
}
}
});
const mergeFiles = function mergeFiles(hash, count) {
return new Promise(async (resolve, reject) => {
const dirPath = `${SERVER_PATH}/${hash}`;
if(! fs.existsSync(dirPath)) { reject('You haven't uploaded the file yet, please upload the file first');
return;
}
const filelist = fs.readdirSync(dirPath);
if (filelist.length < count) {
reject('The file has not been uploaded yet, please try again later');
return;
}
let suffix;
filelist.sort((a, b) = > {
const reg = /_(\d+)/;
return reg.exec(a)[1] - reg.exec(b)[1];
}).forEach(item= > {
!suffix ? suffix = /\.([0-9a-zA-Z]+)$/.exec(item)[1] : null;
// Read each file and append it to a new file named hash
fs.appendFileSync(`${SERVER_PATH}/${hash}.${suffix}`, fs.readFileSync(`${dirPath}/${item}`));
fs.unlinkSync(`${dirPath}/${item}`); // Delete the slice file
});
await delay(1000); // Wait 1 second to delete the newly generated folder
fs.rmdirSync(dirPath);
resolve({
path: `${HOSTNAME}/upload/${hash}.${suffix}`.filename: `${hash}.${suffix}`})}); } router.post('/upload_chunk'.async (ctx, next) => {
try {
let {
files,
fields
} = await multipartyUpload(ctx.req, false);
let file = (files && files.file[0) | | {};let filename = (fields && fields.filename[0) | |' ';
let [, hash] = /^([^_]+)_(\d+)/.exec(filename);
const dirPath = `${SERVER_PATH}/${hash}`;
if(! fs.existsSync(dirPath)) { fs.mkdirSync(dirPath); }const filePath = `${dirPath}/${filename}`;
const isExists = await exists(filePath);
if (isExists) {
ctx.body = {
code: 0.message: 'File already exists'.originalFilename: filename,
serverPath: filePath.replace(__dirname, HOSTNAME)
}
return;
}
await wirteFile(filePath, file, true);
ctx.body = {
code: 0.message: 'File uploaded successfully'.serverPath: filePath.replace(__dirname, HOSTNAME)
}
} catch (err) {
ctx.body = {
code: 1.message: err
}
}
});
// Merge the slice files
router.post('/upload_merge'.async (ctx, next) => {
const {
hash,
count
} = await parsePostParams(ctx.req);
const {
path,
filename
} = await mergeFiles(hash, count);
ctx.body = {
code: 0.message: 'File uploaded successfully',
path,
filename
}
});
router.get('/uploaded'.async (ctx, next) => {
try {
const {
hash
} = ctx.request.query;
const dirPath = `${SERVER_PATH}/${hash}`;
const filelist = fs.readdirSync(dirPath);
filelist.sort((a, b) = > {
const reg = /_([\d+])/;
return reg.exec(a)[1] - reg.exec(b)[1];
});
ctx.body = {
code: 0.message: 'Achieve success',
filelist
}
} catch (err) {
ctx.body = {
code: 0.message: 'Failed to obtain'}}}); app.use(koastatic('/'));
app.use(router.routes());
app.use(router.allowedMethods());
Copy the code