nodejs学习笔记

78次阅读

共计 4598 个字符,预计需要花费 12 分钟才能阅读完成。

http 模块,url 模块

var http=require('http');
var url=require('url');

http.createServer(function(req,res){res.writeHead(200,{"Content-Type":"text/html;charset=utf-8"});
    var str='<ul>';
    for(i=1;i<=10;i++){str+='<li>'+i+'</li>';}
    str+='</ul>';
    res.write(str);
    if(req.url.indexOf('favicon.ico') == -1){var result=url.parse(req.url,true);
        console.log('aid='+result.query.aid)
    }

    res.end();}).listen(9999);
/*
    调试流程:写好页面之后 cd 到该文件目录,node server.js 就能运行,但是每次修改都需要再次运行很麻烦,可以全局安装一个插
    件,自动刷新
    npm install -g supervisor
    cd 到文件目录 supervisor server.js
    ctrl+c 停止进程

    http 模块
    http 模块 node 本身自带,利用 createServer 方法可以创建 http 服务器,带两个参数,req 是请求参数,res 是返回参数,res.write 写入内容,res.end() 结束响应
    每次浏览器访问会有两个请求一次是访问页面一次是获取 favicon.ico 图标,因此需要通过 req 中的 url 进行判断,如果
    是后者则不打印信息,否则控制台会打印两次

    url 模块
    url 模块也是 node 自带,有三个方法:
    url.parse(url,true) 可以把请求地址转化为对象,后面的 true 可以把 query 参数的内容转化为对象
    url.format(urlObject) 与 parse() 正好相反,会把含有请求地址的对象转化为网址
    url.resolve('http://www.baidu.com','news') 替换路径, 输出 http://www.baidu.com/news
    如果地址本身自带二级目录会被覆盖 http://www.baidu.com/nav -> http://www.baidu.com/news
*/

自定义模块

//tools.js
var tools={add:function(x,y){return x+y;},
    sayHello:function(){return '你好,nodejs';}
};
// exports.tools=tools;
module.exports=tools;
//common1.js
var http=require('http');
var tools=require('./tools');
// 如果 foo.js 不在根目录下会自动在 node_modules 文件夹下面找
var foo=require('foo');
// 如果 bar.js 在 node_modules 下的 bar 文件夹下就需要 bar/bar 这样写,如果有 package.json 文件就可以省略
var bar=require('bar');

http.createServer(function(req,res){res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'});
    res.write('你好,nodejs');
    if(req.url.indexOf('favico') == -1){var sum=tools.add(5,16);
        console.log(sum)
        console.log(bar.str)
    }
    res.end();}).listen(9998);

/*
    在 commonjs 规范下引入模块,自定义模块
    通过 require 引入,根目录下使用./ 找到文件,不在根目录下的文件会自动从 node_modules 文件夹内寻找,node_modules 下面还有文件夹怎么办?cd 到那个文件夹(本例是 bar)输入 npm init --yes 会自动生成一个 package.json 文件,里面的 main 是入口文件,有了这个 json 文件就不需要根据
    目录找寻存放在 node_modules 下多级文件夹下的文件,require 的时候直接把文件夹的名字写入就可以

    暴露模块
    exports foo=foo; 使用的时候会多一层对象, 例如 tools.tools.add()
    module.exports=foo; 可以直接找到模块内的变量或者函数例如 tools.add()
*/

fs 模块 – 文件基本操作

var http=require('http');
var fs=require('fs');

http.createServer(function(req,res){res.writeHead(200,{"Content-Type":"text/html;charset=utf-8"});
    if(req.url.indexOf('favicon.ico') == -1){fs.stat('html',function(err,stats){if(err){console.log(err)
            }else{console.log('文件:'+stats.isFile())
                console.log('目录:'+stats.isDirectory())
            }
        })

        fs.mkdir('css', function(err){if(err){console.log(err);
                return false;
            }
            console.log('创建成功');
        });

        fs.writeFile('t.txt','你好,nodejs',function(err){if(err){console.log(err)
                return;
            }
            console.log('写入成功')
        });

        fs.appendFile('t1.txt','不存在就创建 \n', 'utf8', function(err){if(err){console.log(err)
                return;
            }
            console.log('追加成功')
        });

        fs.readFile('html/index.html',function(err,data){if(err){console.log(err)
                return;
            }
            console.log('读取成功')
            console.log(data.toString())
        });

        fs.readdir('html',function(err,data){if(err){console.log(err)
                return;
            }
            console.log('读取成功')
            console.log(data)
        });

        fs.rename('html/index2.html', 'html/newsName.html', function(err){// 改名 剪切
            if(err){console.log(err)
                return;
            }
            console.log('改名成功')
        });

        fs.rename('html/newName.html', 'html2/newName.html', function(err){// 改名 剪切
            if(err){console.log(err)
                return;
            }
            console.log('剪切成功')
        });

        fs.rmdir('delmkdir', function(err){if(err){console.log(err)
                return;
            }
            console.log('删除目录成功')
        });

        fs.unlink('remove.txt', function(err){if(err){console.log(err)
                return;
            }
            console.log('删除文件成功')
        });

        
        // 示例:判断 upload 文件夹是否存在,不存在就创建
        fs.stat('upload',function(err,stu){if(err){fs.mkdir('upload',function(err2){if(err2){console.log(err2);
                        return false;
                    }
                    console.log('创建成功!');
                });
            }else{console.log('目录已经存在!');
            }
        })

        
        // 示例:获取文件目录,并且打印出文件类型(文件 / 目录)fs.readdir('html',function(err,data){if(err){console.log(err);
                return;
            }
            // 方式 1 循环 + 自治性函数
            for(i=0;i<data.length;i++){(function getFileType(nums){fs.stat(data[nums],function(err,stau){// 异步操作
                        if(stau.isDirectory()){console.log(data[nums]+'是目录');
                        }else{console.log(data[nums]+'是文件');
                        }
                    })
                })(i);
            }

            // 方式 2 递归自执行函数
            (function getFileType(nums){if(nums >= data.length){return false;}
                fs.stat('html/'+data[nums],function(err,stau){if(stau.isDirectory()){console.log(data[nums]+'是目录');
                    }else{console.log(data[nums]+'是文件');
                    }
                    getFileType(nums+1);
                })
            })(0);
        });

        
        //fs.stat 的操作类似下面的代码,会输出 3 个 3
        for(i=0;i<3;i++){setTimeout(function(){console.log(i)
            },500)
        }
    }
    res.end();}).listen(9999);

/*
    fs.stat(path, options, function(err,stau){});——检测是文件还是目录,异步操作
    fs.mkdir(path, mode, function(err){});——创建目录
    fs.writeFile(path, data, options, function(err){});——写入文件(会覆盖)fs.appendFile(path, data, options, function(err){});——追加文件
    fs.readFile(path, options, function(err,data){});——读取文件,通过 toString() 转换为字符串
    fs.rmdir(path, function(err,data){});——读取目录
    fs.rename(oldPath, newPath, function(err){});——重命名文件,剪切文件
    fs.unlink(path, function(err){});——删除文件
    
    在最后一个示例中因为 fs.stat 是异步操作,因此要使用自执行函数,把异步操作转换为同步操作,分为两种形式循环 + 自
    执行函数和递归自执行函数,需要注意的是在获取到目录后判断文件类型的时候要加上目录地址, 否则会报错
*/

fs 模块 – 文件流

正文完
 0

node.js学习笔记

79次阅读

共计 5724 个字符,预计需要花费 15 分钟才能阅读完成。

最近一直在学习 node.js,所以总结了一些笔记,记录在这里。

模块化和作用域
node 中常用到的模块
ffer
File
Http
stream

模块化和作用域
this
浏览器中的 this 指的是 windownode 脚本文件中未定义时全局的 this 指向 global,定义时指的是 module.exports
a = 10
console.log(global.a) // 10

全局作用域
没用用 var let const 定义的声明的都是全局作用域
模块作用域
使用变量修饰的都是模块作用域

函数作用域
块级作用域

Buffer
处理二进制数据
// 数组拼接 buffer
var rs = require(‘fs’).createReadStream(‘test.txt’, { highWaterMark: 10})
var data = []
rs.on(‘data’, function (chunk) {
data.push(chunk)
})
rs.on(‘end’, function (chunk) {
var buf = Buffer.concat(data)
console.log(buf.toString())
})
File System
readFile
用来异步读取文本文件中的内容,会将一个文件的全部内容都读到内存中,适用于体积较小的文本文件;读取大文件,使用 stream,readFileSync 直接返回文本数据内容

readFile 第一个参数是文件名,如果没有回自动创建。
fs.stat 获取文件的状态

通常开发者可以在调用 open() read() 或者 write 方法之前调用 fs.stat 方法,用来判断该文件是否存在。fs.stat 和 fs.fstat 功能是一样的,
区别是 fstat 方法第一个参数是文件描述符,格式为 integer,fstat 方法通常搭配 open 方法使用,因为 open 方法返回的结果就是一个文件描述。
var fs= require(‘fs’)
var data = fs.readFileSync(‘test.txt’, {encoding: ‘utf-8’})
console.log(data)

fs.writeFile(‘foo.txt’, “hello world”, {flag: ‘a’, encoding: ‘utf-8’},
function (err) {
if(err) {
console.log(err)
return
}
console.log(‘success’)
})
fs.stat
// 用来获取文件的状态 来判断文件是否存在
// 常在调用 open read witer 是调用
fs.stat(“foo.txt”, function(err, result) {
if(err) {
console.log(err)
return
}
console.log(result)
})

// fs.fstat

fs.open(“foo.txt”,’a’,function(err,fd){
if(err){
console.log(err);
return;
}
console.log(fd);
fs.fstat(fd,function(err,result){
if(err){
console.log(err);
return;
}
console.log(result);
})
})
// 例子
// 获取目录下的说有文件名。
// fs.readdir 和 fs.stat 两个 api
var fs = require(“fs”);
function getAllFileFromPath(path) {
fs.readdir(path, function (err, res) {
for (var subPath of res) {
var statObj = fs.statSync(path + “/” + subPath); // 这里使用了同步方法而非异步
if (statObj.isDirectory()) {// 判断是否为文件夹
console.log(“Dir:”, subPath);
getAllFileFromPath(path + “/” + subPath)// 如果是文件夹,递归获取子文件夹中的文件列表
} else {
console.log(“File:”, subPath);
}
}
})
}
getAllFileFromPath(__dirname);
http
var http = require(‘http’)
var server =http.createServer(function(req, res) {
// 处理 http 请求
var method = req.method
var url = req.url
console.log(method, url)
res.writeHead(200, {‘content-type’: ‘text/plain’})
res.end(‘hello node!’)
})
// 监听来自客户端的事件
server.on(‘connection’, function(req, res) {
console.log(‘connection’)
})
server.on(‘request’, function(req, res) {
console.log(‘request’)
})
server.listen(8080)

// 当访问 8080 时,控制台输出
// connected
// request
// request 打印两次是因为其中一个是 favicon.ico 的请求
// 一个简单的静态服务器
var http = require(‘http’)
var fs = require(‘fs’)
var server = http.createServer(function (req, res) {

if (req.url == ‘/’) {// 访问 8080
var fileList = fs.readdirSync(‘./’)
res.writeHead(200, { ‘content-type’: ‘text/plain’})
// 将数组转化为字符串返回
res.end(fileList.toString())
} else {
var path = req.url;
// 在路径字符串前加. 表示当前目录,避免在 nix 系统访问 / 文件夹
fs.readFile(‘.’ + path, function (err, data) {
if (err) {
res.end(‘ 不存在 ’)
throw err;
}
res.writeHead(200, { ‘content-type’: ‘text/plain’})
res.end(data)
})
}

})
//1buffer.js,2http.js,3httpexmple.js,4.js,foo.txt,login.html,md.md,readFile.js,test.txt,this.js,upload.js
server.listen(8080)
// 处理异常
process.on(‘uncaughtException’, function() {
console.log(‘got error’)
})
处理 http 请求
method url header
get post put delete update
// 处理 http 请求
var method = req.method
var url = req.url
Response 对象
上传数据
upload.html
<form action=”/upload” method=”post” enctype=”multipart/form-data”>
<input type=”file” name=”file”/>
<br/>
<input type=”text” name=”kind”>
<input type=”submit” name=”submit” value=”submit”/>
</form>
js
// npm 安装依赖 formidable
var http = require(‘http’)
var fs = require(‘fs’)
var formidable = require(“formidable”);
var server = http.createServer(function (req, res) {
if (req.url == ‘/upload’) {
switch (req.method) {
case ‘GET’:
fs.createReadStream(‘upload.html’).pipe(res)
break
case ‘POST’:
dealpost(req, res) // 自定义方法处理
break
default:
console.log(‘other request’)
}
} else {
res.writeHead(302, {
‘Location’: ‘./upload’
})
res.end() // 将所有的 url 访问都转到 /login 路径
}
})

function dealpost(req, res) {
var form = new formidable.IncomingForm();
form.keepExtensions = true
form.uploadDir = __dirname
form.parse(req, function(err, fields, files) {
if(err) {
throw err
}
console.log(fields)
console.log(files)
res.writeHead(200, {‘content-type’: ‘text/plain’})
res.end(‘upload finished’)
})
}
server.listen(8080)
stream
stream 模块是 node 操作流失数据
四种基础的 stream 类型

readable 可读流
writable 可写流
duplex 即可读又可写的流
transform 操作写入的数据,然后读取结果,通常用于数据数据和输出数据不要求匹配的场景,

var stream =require(‘stream’)
var fs = require(‘fs’)
var readStream = fs.createReadStream(“./text.txt”, ‘utf-8’)
readStream.on(‘data’, function(data) {
console.log(data)
})
readStream.on(‘close’, function() {
console.log(‘close’)
})
readStream.on(‘error’, function() {
console.log(‘error’)
})
当创建一个可读流读取一个较大的文件,在调用 pipe 方法将数据通过一个可写流写入另一个位置。如果读取的速度大于写入的速度,那么 node 将会在内存中缓存这些数据。
pipe 方法相当于在可读流和可写流之间加起来的桥梁,是的数据可以通过管道由可读流进入可写流,
使用 pipe 改写的静态文件服务器
var stream = require(‘stream’)
var http = require(‘http’)
var fs = require(‘fs’)
var server = http.createServer(function (req, res) {
if (req.url == ‘/’) {
var fileList = fs.readdirSync(‘./’)
res.writeHead(200, { ‘Content-type’: ‘text/plain’})
res.end(fileList.toString())
} else {
try {
var readStream = fs.createReadStream(path).pipe(res);
} catch (e) {
res.end(“file not exists”);
}
}
})
server.listen(3000)
console.log(“Listening on 3000”);

// 处理异常
process.on(“uncaughtException”, function () {
console.log(“got error”);
})

// pipe 方法接收一个 writable 对象,当 readable 对象调用 pipe 方法时,会在内部调用 writable 对象的 write 方法进行写入。
Events
事件和监听器
eventsnode 程序中的对象会产生一系类的事件,他们被称为事件触发器,
所有能触发事件的对下你给都是 eventEmitter 类的实例。eventEmitter 定义了 on 方法。
var eventEmitter = require(“events”);
var myEmitter = new eventEmitter();
myEmitter.on(“begin”,function(){
console.log(“begin”);
})
myEmitter.emit(“begin”);
第五章
中间件 middleware
1 中间价的概念
express 本身是有路由和中间件构成的,从本质上来说,express 的运行就是在不断调用这个中间件。
中间件的本质上是接收请求并且做出相应动作的函数,该函数通常接收 req 和 res 作为参数,以便对 request 和 response 对象进行操作,在 web 应用中,客户端发起的每一个请求,首先要经过中间件的处理才能继续向下。
中间件的第三个参数一般写作 next, 它代表一个方法,即下一个中间件。如果我们在中间件的方法体中调用了 next 方法,即表示请求会经过下一个中间件处理。
2 中间件的功能
中间件是一个函数,可以做到 node 代码能做到的任何事情,除此之外还包括修改 request 和 response 对象、终结请求 - 响应循环,以及调用下一个中间件等功能,这通常是通过在内部调用 next 方法来实现的。如果某个中间件中没有调用 next 方法,则表示对请求的处理到此为止,下一个中间件不会被执行。
中间件的加载
中间件的加载使用 use 方法来实现,改方法定义在 express 或者 koa 对象的实例上,
var app =express()
app.use(md)
express 中的中间件
express 应用可使用如下几种中间件

应用级中间件
路由级中间件
错误处理中间件
内置中间件
第三方中间件

应用级中间件 使用 app.use 方法,绑定在 app 对象上的中间件
路由级中间件 路由处理是 express 的一部分,koa 是通过第三方 koa-router

正文完
 0