zoukankan      html  css  js  c++  java
  • node静态资源服务器的搭建----访问本地文件夹(搭建可访问静态文件的服务器)

    我们的目标是实现一个可访问静态文件的服务器,即可以在浏览器访问文件夹和文件,通过点击来查看文件。

    1.先创建一个文件夹anydoor,然后在该文件夹里npm init一个package.json文件,按如下图所示创建文件夹和文件(node_models,package-lock.json是安装生成,不用自己创建)。为了方便管理,我们把一些设置性和公共的参数放在defaultConfig.js里,方便后期的更改和管理,在app.js中创建一个服务器。

    //app.js,(npm install chalk,chalk可以改变console打印的颜色)

    const http = require('http');
    const chalk = require('chalk');
    const config = require('./config/defaultConfig.js');

    var server = http.createServer(function(req,res){
    res.statusCode = 200;
    res.setHeader('Content-type','text/plain');
    res.end('Hello world');
    });

    server.listen(config.port,config.hostname,()=>{
    var addr = `http://${config.hostname}:${config.port}`;
    console.info(`listenning in:${chalk.green(addr)}`);
    })
     这样,一个最简单的http服务器就就搭好了,在src文件夹中运行node app.js,如下图所示

    在浏览器输入http://127.0.0.1:9527,打开控制台就可以看到请求,可以看到我们设置的参数。

    2.接下来,我们着手搭建一个静态资源服务器,可以通过在浏览器地址栏输入地址的方式,访问启动当前服务的文件夹列表和文件夹的内容。在defaultConfig.js中添加一个新的配置项,root,当前node启动的目录。需要注意的是,process.cwd()是当前执行node命令时候的文件夹地址(工作目录),__dirname,是被执行的js 文件的地址 (文件所在目录)。

    //defaultConfig.js

    module.exports = {
    root:process.cwd(),//process.cwd()是当前执行node命令时候的文件夹地址 ——工作目录,__dirname,是被执行的js 文件的地址 ——文件所在目录
    hostname:'127.0.0.1',
    port:9527
    }
    //app.js

    const http = require('http');
    const chalk = require('chalk');
    const path = require('path');
    const fs = require('fs');
    const config = require('./config/defaultConfig.js');

    var server = http.createServer(function(req,res){
    const filePath = path.join(config.root,req.url)
    console.info("path",`${chalk.green(filePath)}`)
    fs.stat(filePath,(err,stats)=>{//fs.stat(path,callback),读取文件的状态;
    if(err){//说明这个文件不存在
    console.log(err)
    res.statusCode = 404;
    res.setHeader('Content-Type','text/javascript;charset=UTF-8');//utf8编码,防止中文乱码
    res.end(`${filePath} is not a directory or file.`)
    return;
    }
    if(stats.isFile()){//如果是文件
    res.statusCode = 200;
    res.setHeader('Content-Type','text/javascript;charset=UTF-8');
    fs.createReadStream(filePath).pipe(res);//以流的方式来读取文件
    }else if (stats.isDirectory()) {//如果是文件夹,拿到文件列表
    fs.readdir(filePath,(err,files)=>{//files是个数组
    res.statusCode = 200;
    res.setHeader('Content-Type','text/plain');
    res.end(files.join(','));//返回所有的文件名
    })
    }
    })
    });

    server.listen(config.port,config.hostname,()=>{
    var addr = `http://${config.hostname}:${config.port}`;
    console.info(`listenning in:${chalk.green(addr)}`);
    })
    以我的本地文件为例,我的启动的app.js文件在“D:studyCommonanydoorsrc”中,我在浏览器访问http://127.0.0.1:9527/,所以我的root就是D:studyCommonanydoorsrc,src是文件夹,在浏览器看到的就是D:studyCommonanydoorsrc里的文件列表。

    同理,在浏览器中访问http://127.0.0.1:9527/app.js,root就是D:studyCommonanydoorsrcapp.js,app.js是一个文件,浏览器看到的就是app.js的详细内容。

    依次类推,当然还可以通过改变浏览器url查看config文件夹,以及config文件夹里的defaultConfig.js文件。

    3.至此,一个静态资源服务器已经具备完整功能了,接下来我们优化,完善一下代码,也优化一下功能,让他看起来更高大上一些。现在代码有很多的异步回调,我们通过promisify改造一下代码,关于promise化可以看一下这篇博客https://blog.csdn.net/bdss58/article/details/67151775,然后也会用到async/await的知识点。

    首先,将app.js改成如下形式

    const http = require('http');
    const chalk = require('chalk');
    const path = require('path');
    const fs = require('fs');
    const promisify = require('util').promisify;
    const stat = promisify(fs.stat);//stat方法promise化
    const readdir = promisify(fs.readdir);
    const config = require('./config/defaultConfig.js');

    var server = http.createServer(function(req,res){
    const filePath = path.join(config.root,req.url)
    console.info("path",`${chalk.green(filePath)}`)
    try{
    fs.stat(filePath,(err,stats)=>{//fs.stat(path,callback),读取文件的状态;
    if(stats.isFile()){//如果是文件
    res.statusCode = 200;
    res.setHeader('Content-Type','text/javascript;charset=UTF-8');
    fs.createReadStream(filePath).pipe(res);//以流的方式来读取文件
    }else if (stats.isDirectory()) {//如果是文件夹,拿到文件列表
    fs.readdir(filePath,(err,files)=>{//files是个数组
    res.statusCode = 200;
    res.setHeader('Content-Type','text/plain');
    res.end(files.join(','));//返回所有的文件名
    })
    }
    })
    }catch(err){
    if(err){//说明这个文件不存在
    console.log(err)
    res.statusCode = 404;
    res.setHeader('Content-Type','text/javascript;charset=UTF-8');//utf8编码,防止中文乱码
    res.end(`${filePath} is not a directory or file.`)
    return;
    }
    }
    });

    server.listen(config.port,config.hostname,()=>{
    var addr = `http://${config.hostname}:${config.port}`;
    console.info(`listenning in:${chalk.green(addr)}`);
    })
    接下来,promise化,以及把异步方法通过async/await改造成像是同步代码的样子(本质还是异步)。因为await方法必须在aysyn函数中使用,因此我们新建一个async的readFile函数。

    const http = require('http');
    const chalk = require('chalk');
    const path = require('path');
    const fs = require('fs');
    const promisify = require('util').promisify;
    const stat = promisify(fs.stat);//stat方法promise化
    const readdir = promisify(fs.readdir);
    const config = require('./config/defaultConfig.js');

    var server = http.createServer(function(req,res){
    const filePath = path.join(config.root,req.url)
    console.info("path",`${chalk.green(filePath)}`)
    async function readFile(req, res, filePath){
    try{
    const stats = await stat(filePath);//awit必须包含在async函数中,所以把所有代码移到定义的readFile函数中
    if(stats.isFile()){//如果是文件
    res.statusCode = 200;
    res.setHeader('Content-Type','text/javascript;charset=UTF-8');
    fs.createReadStream(filePath).pipe(res);//以流的方式来读取文件
    }else if (stats.isDirectory()) {//如果是文件夹,拿到文件列表
    //将readdir方法也promise化
    const files = await readdir(filePath);
    res.statusCode = 200;
    res.setHeader('Content-Type','text/plain');
    res.end(files.join(','));//返回所有的文件名
    }
    }catch(err){
    res.statusCode = 404;
    res.setHeader('Content-Type','text/javascript;charset=UTF-8');//utf8编码,防止中文乱码
    res.end(`${filePath} is not a directory or file.`)
    return;
    }
    }
    readFile(req, res, filePath);//执行函数

    });

    server.listen(config.port,config.hostname,()=>{
    var addr = `http://${config.hostname}:${config.port}`;
    console.info(`listenning in:${chalk.green(addr)}`);
    })
    在浏览器地址栏依次输入http://127.0.0.1:9527,http://127.0.0.1:9527/app.js,http://127.0.0.1:9527/config,http://127.0.0.1:9527/config/defaultConfig.js,发现效果与原来的异步回调方法是一样的。为了代码结构更清晰,我们在src文件夹下新建helper文件夹,并创建一个readFile.js的文件,把readFile函数移动到这个文件里,并导入到app.js中。

    //src/helper/readFile.js

    const fs = require('fs');
    const promisify = require('util').promisify;
    const stat = promisify(fs.stat);//stat方法promise化
    const readdir = promisify(fs.readdir);
    module.exports = async function(req, res, filePath){
    try{
    const stats = await stat(filePath);//awit必须包含在async函数中,所以把所有代码移到定义的readFile函数中
    if(stats.isFile()){//如果是文件
    res.statusCode = 200;
    res.setHeader('Content-Type','text/javascript;charset=UTF-8');
    fs.createReadStream(filePath).pipe(res);//以流的方式来读取文件
    }else if (stats.isDirectory()) {//如果是文件夹,拿到文件列表
    //将readdir方法也promise化
    const files = await readdir(filePath);
    res.statusCode = 200;
    res.setHeader('Content-Type','text/plain');
    res.end(files.join(','));//返回所有的文件名
    }
    }catch(err){
    console.log(err)
    res.statusCode = 404;
    res.setHeader('Content-Type','text/javascript;charset=UTF-8');//utf8编码,防止中文乱码
    res.end(`${filePath} is not a directory or file.`)
    return;

    }
    }
    //app.js

    const http = require('http');
    const chalk = require('chalk');
    const path = require('path');
    const config = require('./config/defaultConfig.js');
    const readFile = require('./helper/readFile.js');

    var server = http.createServer(function(req,res){
    const filePath = path.join(config.root,req.url)
    console.info("path",`${chalk.green(filePath)}`)
    readFile(req,res,filePath)
    });

    server.listen(config.port,config.hostname,()=>{
    var addr = `http://${config.hostname}:${config.port}`;
    console.info(`listenning in:${chalk.green(addr)}`);
    })
    至此,异步函数的同步写法改造就结束了,但是要访问某个文件夹还得自己在浏览器的地址栏里输入文件名,感觉很不方便,要是能点击页面上的文件名,然后直接跳转到对应文件就好了,接下来我们就实现这个功能。

    4.我们可以通过html字符串拼接的方法来实现这个功能,将文件名的地址拼接在a标签中,点击a标签来实现跳转。因为要写入html标签,所以把Content-Type的Mime类型改为text/html。

    //readFile.js

    const fs = require('fs');
    const promisify = require('util').promisify;
    const stat = promisify(fs.stat);//stat方法promise化
    const readdir = promisify(fs.readdir);
    const config = require('../config/defaultConfig.js');
    module.exports = async function(req, res, filePath){
    try{
    const stats = await stat(filePath);//awit必须包含在async函数中,所以把所有代码移到定义的readFile函数中
    if(stats.isFile()){//如果是文件
    res.statusCode = 200;
    res.setHeader('Content-Type','text/javascript;charset=UTF-8');
    fs.createReadStream(filePath).pipe(res);//以流的方式来读取文件
    }else if (stats.isDirectory()) {//如果是文件夹,拿到文件列表
    //将readdir方法也promise化
    const files = await readdir(filePath);
    res.statusCode = 200;
    res.setHeader('Content-Type','text/html;charset=UTF-8');
    res.write('<html><body><div>')
    var html= '';
    for(let i=0;i<files.length;i++){//
    html+='<a style="display:block" href="http://127.0.0.1:9527'+
    req.url+'/'+files[i]+'">'+files[i]+'</a>';
    }
    res.write(html);//返回所有的文件名
    res.end('</div></body></html>')
    }
    }catch(err){
    console.log(err)
    res.statusCode = 404;
    res.setHeader('Content-Type','text/javascript;charset=UTF-8');//utf8编码,防止中文乱码
    res.end(`${filePath} is not a directory or file.`)
    return;
    }
    }
    现在,如下图所示,我们就可以自由的点击文件和文件名来实现访问,而不需要去地址栏输入地址了。

  • 相关阅读:
    冲刺第二阶段第五天
    找水王2
    冲刺第二阶段第四天
    梦断代码阅读笔记03
    冲刺第二阶段第三天
    冲刺第二阶段第二天
    冲刺第二阶段第一天
    梦断代码阅读笔记02
    第十二周学习进度条
    找水王
  • 原文地址:https://www.cnblogs.com/ygunoil/p/10899511.html
Copyright © 2011-2022 走看看