How to server static files from folder & Upload file save on this folder. #450
Replies: 5 comments 2 replies
-
That snippet works for small files only - if you reach GB of data you have to properly stream the data - and really, you kind of always should stream! |
Beta Was this translation helpful? Give feedback.
-
Look at examples/VideoStreamer.js instead - it shows how you can properly stream huge files with minimal backpressure. |
Beta Was this translation helpful? Give feedback.
-
I just published a small library to serve static files based on this VideoStreamer example, you can check it out here https://www.npmjs.com/package/uwebsocket-serve |
Beta Was this translation helpful? Give feedback.
-
serve static is using
|
Beta Was this translation helpful? Give feedback.
-
I made this: export const getContentType = (filePath: string) => {
const mimeTypes = {
'.html': 'text/html',
'.css': 'text/css',
'.js': 'application/javascript',
'.json': 'application/json',
'.jpg': 'image/jpeg',
'.jpeg': 'image/jpeg',
'.png': 'image/png',
'.gif': 'image/gif',
'.svg': 'image/svg+xml',
'.webp': 'image/webp',
'.avif': 'image/avif',
'.mp4': 'video/mp4',
'.mp3': 'audio/mp3',
'.ogg': 'audio/ogg',
'.wav': 'audio/wav',
'.pdf': 'application/pdf',
'.txt': 'text/plain',
'.zip': 'application/zip',
'.tar': 'application/x-tar',
'.gz': 'application/gzip',
'.xml': 'application/xml',
'.csv': 'text/csv',
'.rar': 'application/x-rar-compressed',
'.7z': 'application/x-7z-compressed',
'.woff': 'font/woff',
'.woff2': 'font/woff2',
'.ttf': 'font/ttf',
'.otf': 'font/otf',
'.eot': 'application/vnd.ms-fontobject',
'.mkv': 'video/x-matroska',
'.flv': 'video/x-flv',
'.ico': 'image/x-icon',
'.mpg': 'video/mpeg',
'.webm': 'video/webm',
'.jsonld': 'application/ld+json',
'.ics': 'text/calendar',
'.rtf': 'application/rtf',
'.md': 'text/markdown',
'.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'.xls': 'application/vnd.ms-excel',
'.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'.doc': 'application/msword',
'.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'.ppt': 'application/vnd.ms-powerpoint',
} as const;
const extname = path.extname(filePath).toLowerCase() as keyof typeof mimeTypes;
return mimeTypes[extname] || 'application/octet-stream';
}
export const serveStatic = async (res: HttpResponse, req: HttpRequest) => {
try {
let aborted = false;
res.onAborted(() => {
aborted = true;
});
const range = req.getHeader('range');
const filePath = path.join(__dirname, '..', '..', req.getUrl());
await fs.promises.access(filePath, fs.constants.F_OK);
const stat = await fs.promises.stat(filePath);
const fileSize = stat.size;
const contentType = getContentType(filePath) as string;
if (range) {
const [start, end] = range.replace(/bytes=/, '').split('-').map(Number);
const chunkStart = start || 0;
const chunkEnd = end || fileSize - 1;
if (chunkStart >= fileSize || chunkEnd >= fileSize) {
res.cork(() => {
res.writeStatus('416').end();
})
return;
}
const stream = fs.createReadStream(filePath, { start: chunkStart, end: chunkEnd });
res.cork(() => {
res.writeStatus('206')
.writeHeader('Access-Control-Allow-Origin', '*')
.writeHeader('Content-Type', contentType)
.writeHeader('Content-Length', `bytes ${chunkStart}-${chunkEnd}/${fileSize}`)
.writeHeader('Content-Length', `${chunkEnd - chunkStart + 1}`)
.writeHeader('Accept-Range', 'bytes')
})
stream.on('data', (chunk) => {
if (!aborted) res.cork(() => { res.write(chunk) })
});
stream.on('end', () => {
if (!aborted) res.cork(() => { res.end() })
});
stream.on('error', () => {
if (!aborted) res.cork(() => { res.writeStatus('500').end() })
});
} else {
res.cork(() => {
res.writeStatus('200')
.writeHeader('Access-Control-Allow-Origin', '*')
.writeHeader('Content-Type', contentType)
.writeHeader('Content-Length', `${fileSize}`)
.writeHeader('Cache-Control', 'public, max-age=3600')
.writeHeader('Last-Modified', stat.mtime.toUTCString())
})
const stream = fs.createReadStream(filePath);
stream.on('data', (chunk) => {
if (!aborted) res.cork(() => { res.write(chunk) })
});
stream.on('end', () => {
if (!aborted) res.cork(() => { res.end() })
});
stream.on('error', () => {
if (!aborted) res.cork(() => { res.writeStatus('500').end() })
});
}
} catch (error: any) {
console.log(error);
res.cork(() => { res.writeStatus('404').end('File not found') });
}
}
App.get('/public/*', serveStatic);
//modify filePath to your original path.
//I believe this will handle large file, and also streams etc, i also made a function to attach form-data to req.files, and json to req.body, don't know if that is needed. |
Beta Was this translation helpful? Give feedback.
-
I am stuck at following problem
My app have 4 api so I don't want to manage another server for this :)
Thank you.
Beta Was this translation helpful? Give feedback.
All reactions