MIME - Multipurpose Internet Mail Extensions , 它是描述消息内容的类型的因特网标准。
http://www.w3school.com.cn/media/media_mimeref.asp
我们之前在代码中设置的“Content-Type”, 为 "text/plain" 与 "text/html" 。就是设置两种不同的MIME 。
我们常用的还有 “application/javascript” (javascript), "image/png"(png), "image/jpeg" 。
浏览器可以根据Content-Type 来解析传递过来的数据。
之前的代码里,我们是直接指定,res 的Content-Type 为一个字符串的。下面我们在一个模块里统一定一下MIME,然后在需要的地方引入。
我们在 src/helper 下新建一个文件 mime.js , 在mime.js 里面定义好mime 类型,然后export 一个方法根据扩展名返回MIME 类型。如下。
const path = require('path');
const mimeType = {
'css': 'text/css',
'gif': 'image/gif',
'html': 'text/html',
'ico': 'image/x-icon',
'jpeg': 'imag/jpeg',
'jpg': 'image/jpeg',
'json': 'application/json',
'js': 'text/javascript',
'pdf': 'application/pdf',
'png': 'image/png',
'svg': 'image/svg+xml',
'swf': 'application/x-shockwave-flash',
'tiff': 'image/tiff',
'txt': 'text/plain',
'wav': 'audio/x-wav',
'wma': 'audio/x-ms-wma',
'wmv': 'video/x-ms-wmv',
'xml': 'text/xml'
}
module.exports = (filePath) => {
let ext = path.extname(filePath).split('.').pop().toLowerCase();
if(!ext) {
ext = filePath;
}
return mimeType[ext] || mimeType['txt'];
}
好,然后,我们去使用MIME 的地方去试一试。src/helper 下的 route.js 。如下。
const fs = require('fs');
const path = require('path');
const ejs = require('ejs');
const promisify = require('util').promisify;
const conf = require('../config/defaultConfig');
const mime = require('./mime');
const stat = promisify(fs.stat);
const readdir = promisify(fs.readdir);
const ejsPath = path.join(__dirname, '../templates/main-page.ejs');
const source = fs.readFileSync(ejsPath,'utf-8');
module.exports = async function (req, res, filePath) {
try {
const stats = await stat(filePath);
if (stats.isFile()) {
const contentType = mime(filePath);
res.statusCode = 200;
res.setHeader('Content-Type', contentType);
fs.createReadStream(filePath).pipe(res)
}
if (stats.isDirectory()) {
const files = await readdir(filePath);
res.statusCode = 200;
res.setHeader('Content-Type', 'text/html');
const dir = path.relative(conf.root, filePath)
const data = {
title: path.basename(filePath),
dir: dir ? `/${dir}` : '',
files
};
res.end(ejs.render(source, data));
}
} catch(ex) {
res.statusCode = 404;
res.setHeader('Content-Type', 'text/plain');
res.end(`${filePath} is not a file or directory`);
}
}
为了美观,我们可以为每个file 添加一个图标。在route.js 中可以这样写。
const fs = require('fs');
const path = require('path');
const ejs = require('ejs');
const promisify = require('util').promisify;
const conf = require('../config/defaultConfig');
const mime = require('./mime');
const stat = promisify(fs.stat);
const readdir = promisify(fs.readdir);
const ejsPath = path.join(__dirname, '../templates/main-page.ejs');
const source = fs.readFileSync(ejsPath,'utf-8');
module.exports = async function (req, res, filePath) {
try {
const stats = await stat(filePath);
if (stats.isFile()) {
const contentType = mime(filePath);
res.statusCode = 200;
res.setHeader('Content-Type', contentType);
fs.createReadStream(filePath).pipe(res)
}
if (stats.isDirectory()) {
const files = await readdir(filePath);
res.statusCode = 200;
res.setHeader('Content-Type', 'text/html');
const dir = path.relative(conf.root, filePath)
const data = {
title: path.basename(filePath),
dir: dir ? `/${dir}` : '',
files: files.map((file) => {
return {
file,
icon: mime(file)
}
})
};
res.end(ejs.render(source, data));
}
} catch(ex) {
res.statusCode = 404;
res.setHeader('Content-Type', 'text/plain');
res.end(`${filePath} is not a file or directory`);
}
}
然后,我们去改一下模板,如下。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
body {
margin: 30px;
}
a {
display: block;
font-size: 15px;
}
</style>
</head>
<body>
<% files.map( file => { %>
<a href="<%= dir %>/<%= file %>"> [<%= file.icon %>] <%= file.file %> </a>
<% }) %>
</body>
</html>
当然,可以根据icon 添加小图标的,就不演示了。