Node.js学习总结

目录

一、http

get 请求处理

post请求

二、fs文件读写

读小文件

写文件

判断是否有文件存在、判断文件是否是文件夹还是文件

流读写文件 stream

压缩文件

解压文件 

 

三、url模块

四、router学习

五、网络编程

状态码

Node内置的模块,对应的网络通信方式

构建TCP服务

六、events 模块

 七、异步控制流

callback形式

Promise对象

async/await

八、web应用基础

 1.cookie

九、Buffer

Buffer转字符串

字符串转Buffer

Buffer拼接


一、http

node.js学习篇之url解析

//原生模块
var http = require('http');
var url = require('url');
var querystring = require('querystring');

http.createServer(function(req, res){
	//第二个参数(可省)传入一个布尔值,默认为false,为true时,返回的url对象中,query的属性为一个对象
	var urlObj = url.parse(req.url, false);
	var query = urlObj.query;
	// querystring.parse 解析请求格式:
	var qsObj = querystring.parse(query);
	console.log(query, urlObj, qsObj);//只会在node终端log出来,而不是浏览器
	res.end('Hello Node');
}).listen(8080);

get 请求处理

var http = require('http');
var url = require('url');
var util = require('util');
 
http.createServer(function(req, res){
    res.writeHead(200, {'Content-Type': 'text/plain;charset=uft-8'});
 
    // 解析 url 参数
    req.query = url.parse(req.url, true).query;
    res.write("foo:" + req.query.foo);
    //res.write("\n");
    res.write("hello" + req.query.hello);
    res.end();
 
}).listen(8080);

post请求

util.inspect(object,[showHidden],[depth],[colors]) 是一个将任意对象转换 为字符串的方法,通常用于调试和错误输出。它至少接受一个参数 object,即要转换的对象。

var http = require('http');
var util = require('util');
var querystring = require('querystring');

http.createServer(function(req, res){
    // PostData
    var PostData = '';     

    // 通过req的data事件监听函数,每当接受到请求体的数据,就累加到post变量中
    req.on('data', (chunk) => {    
        PostData += chunk;
    });

    // 在end事件触发后,通过querystring.parse将post解析为真正的POST请求格式,然后向客户端返回。
    req.on('end', () => {    
        PostData = querystring.parse(PostData);
        res.end(util.inspect(PostData));
    });
}).listen(8080);

二、fs文件读写

读小文件

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

var filename = path.resolve(__dirname, 'data.txt');

fs.readFile(filename,(err, data) =>{
    if(err) {
        console.error(err);
        return;
    }
    console.log(data.toString());
});

写文件

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

const filename = path.resolve(__dirname,'data.txt');

const content = '新内容';
//追加写入为a,覆盖写入为w
const opt = {
    flag : 'a'
}
fs.writeFile(filename, content, opt ,(err)=> {
    console.error(err);
} );

判断是否有文件存在、判断文件是否是文件夹还是文件

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

const filename = path.resolve(__dirname, 'data.txt');

fs.exists(filename, exist => {
   console.log('exist', exist);
});

fs.stat(filename, function (err, stats) {
    if (err) {
        return console.error(err);
    }
    console.log(stats);
    console.log("读取文件信息成功!");
    
    // 检测文件类型
    console.log("是否为文件(isFile) ? " + stats.isFile());
    console.log("是否为目录(isDirectory) ? " + stats.isDirectory());    
 });

流读写文件 stream

//写文件
//readStream.pipe(writeFilename);
setTimeout(() => {
    readStream.pipe(writeStream);
}, 0);

var path = require('path');
var fs = require('fs');
//读文件路径
const filename = path.resolve(__dirname, 'data.txt');
//写文件路径
const writeFilename = path.resolve(__dirname, 'dataNew.txt');

const readStream = fs.createReadStream(filename, {encoding : 'utf8'});
const writeStream = fs.createWriteStream(writeFilename);

//写文件
//readStream.pipe(writeFilename);
setTimeout(() => {
    readStream.pipe(writeStream);
}, 0);

//读取文件发生错误事件
readStream.on('error', (err) => {
    console.log('发生异常:', err);
});

//已打开要读取的文件事件
readStream.on('open', (fd) => {
    console.log('文件已打开:', fd);
});

//文件已经就位,可用于读取事件
readStream.on('ready', () => {
    console.log('文件已准备好..');
});


//文件读取中事件·····
readStream.on('data', (chunk) => {
    console.log('读取文件数据:', chunk);
});
 
//文件读取完成事件
readStream.on('end', () => {
    console.log('读取已完成..');
});
 
//文件已关闭事件
readStream.on('close', () => {
    console.log('文件已关闭!');
});

压缩文件

const fs = require("fs");
//压缩和解压的模块
const zlib = require('zlib');
const path = require('path');

// 压缩 data.txt 文件为 data.txt.gz
// 以流的方式读取文本
const filename = path.resolve(__dirname,'data.txt');
fs.createReadStream(filename)
  .pipe(zlib.createGzip()) //把读取出来的文本调用压缩模块进行压缩
  .pipe(fs.createWriteStream('data.zip'));//把压缩好的流进行保存

console.log("压缩完成。");

解压文件 

 

const fs = require("fs");
//压缩和解压的模块
const zlib = require('zlib');
const path = require('path');

const filename = path.resolve(__dirname,'../','data.zip');
console.log(filename);

fs.createReadStream(filename)
  .pipe(zlib.createGunzip())
  .pipe(fs.createWriteStream('datayasuohaha.txt'));

console.log("文件解压完成。")

三、url模块

  • url.parse(urlstring, boolean)
  • 参数
    • urlstring:字符串格式的 url
    • boolean:在 url 中有参数,默认参数为字符串,如果此参数为 true,则会自动将参数转转对象
  • 常用属性
    • href: 解析前的完整原始 URL,协议名和主机名已转为小写
    • protocol: 请求协议,小写
    • host: 服务器的域名或者ip地址,包括端口信息,小写。默认localhost
    • hostname: 服务器的名称,小写
    • port: 服务器的端口号
    • pathname: URL中路径,下面例子的 /one
    • search: 查询对象,即:queryString,包括之前的问号“?”
    • path: pathname 和 search的合集,请求路径,默认为/
    • query: 查询字符串中的参数部分(问号后面部分字符串),或者使用 querystring.parse() 解析后返回的对象
    • hash: 锚点部分(即:“#”及其后的部分)
var url = require('url');

//http://localhost:8000/start?foo=bar&hello=word

//第二个参数为 true =>  { foo: 'bar', hello: 'wordk' } - urlObj.query 为一个对象
var urlObj = url.parse('http://localhost:8000/start?foo=bar&hello=wordk', true);
console.log("urlObj true", urlObj);

//第二个参数为 false - urlObj.query 为一个字符串 =>  { foo: 'bar', hello: 'wordk' }
urlObj = url.parse('http://localhost:8000/start?foo=bar&hello=wordk', false);

/*
*传入的URL对象会做以下处理:
*
*href 属性会被忽略
*protocol无论是否有末尾的 : (冒号),会同样的处理
*这些协议包括 http, https, ftp, gopher, file 后缀是 :// (冒号-斜杠-斜杠).
*所有其他的协议如 mailto, xmpp, aim, sftp, foo, 等 会加上后缀 : (冒号)
*auth 如果有将会出现.
*hostname 如果 host 属性没被定义,则会使用此属性.
*port 如果 host 属性没被定义,则会使用此属性.
*host 优先使用,将会替代 hostname 和port
*pathname 将会同样处理无论结尾是否有/ (斜杠)
*search 将会替代 query属性
*query (object类型; 详细请看 querystring) 如果没有 search,将会使用此属性.
*search 无论前面是否有 ? (问号),都会同样的处理
*hash无论前面是否有# (井号, 锚点),都会同样处理

四、router学习

  1. 注册一个账户 --> [post] --> http://localhost:8080/register
  2. 注册成功的情况下跳转到登录界面进行登录 --> [post] --> http://localhost:8080/login
  3. 登录成功进行获取用户信息 --> [get] --> http://localhost:8080/user
  4. 同时可以获取博客信息 --> [get] --> http://localhost:8080/blogs
  5. 如何访问不存在的路由则抛出错误信息。


const http = require('http')
const url = require('url')
const querystring = require('querystring');
const util = require('util');

const server = http.createServer((req, res) => {
    let urlObj = url.parse(req.url, true);
    let pathname = urlObj.pathname;
    let method = req.method.toUpperCase();
    let params = urlObj.query;
    if(method === 'POST'){
        let postData = '';
        req.on('data', (chunk) => {
            postData += chunk;
        });
        req.on('end', () => {
            postData = querystring.parse(postData);
            let result = {};
            switch(pathname) {
                case '/login':
                    //连接数据库,实现登陆逻辑
                    result = {status: true,
                              message : '/login'};
                    break;
                case '/register':
                    //连接数据库,实现注册逻辑
                    result = {status: true,
                              message : '/register'};
                    break;
                default :
                    result = {status: false, 
                               message: '没有对应的请求'};
                    break;
            }
            res.writeHead(200, {'Content-Type': 'text/plain;charset=uft-8'});
            res.end(JSON.stringify(result));
        });
    } else if(method === 'GET') {
        let result = {};
        switch(pathname){
            case '/user':
                //连接数据库,获取用户信息
                result = {status: true,
                          data: [],
                          message : '/user',
                          params};
                break;
            case '/blogs':
                //连接数据库,获取博客信息
                result = {status: true, 
                          data: [], 
                          message : '/blogs',
                          params};
                break;
            default :
                result = {status: false,
                          message: '没有对应的请求', 
                          params};
                break;
        }
        res.writeHead(200, {'Content-Type': 'text/plain;charset=uft-8'});
        res.end(JSON.stringify(result));
    }
});

server.listen(8080);

五、网络编程

状态码

1XX2XX3XX4XX5XX
信息性状态码成功状态码重定向客户端错误状态码服务端错误状态码
少见200 OK301 永久性重定向400 请求报文语法错误500服务器请求错误
 204 响应报文不含实体的主体部分302 临时性重定向(负载均衡)401发送的请求需要有通过 HTTP 认证的认证信息 307 和302含义相同503 服务器暂时处于超负载或正在停机维护,无法处理请求
 206 范围请求303 资源存在着另一个 URL,应使用 GET 方法定向获取资源403 对请求资源的访问被服务器拒绝 
  304 客户端已经执行了GET,但文件未变化。404 服务器上没有找到请求的资源

Node内置的模块,对应的网络通信方式

模块服务
netTCP
dgramUDP
httpHTTP
httpsHTTPS

构建TCP服务

TCP全名为传输控制协议。

ps:书上《深入浅出node.js》这个TCP服务的事件介绍的挺好的,就直接拿过来了。(*^▽^*)

这里代码写的有点乱,后面再更新上来。嘿嘿

六、events 模块

// 引入 events 模块
var events = require('events');
// 创建 eventEmitter 对象
var eventEmitter = new events.EventEmitter();

// 绑定事件及事件的处理程序
eventEmitter.on('connection', function(){
    console.log('log: 连接成功。');
	// 触发 data_received 事件
	eventEmitter.emit('data_received');
});


eventEmitter.on('data_received', function(){
	console.log('log: 数据接收成功。');
});

//用 eventEmitter 对象的 emit 方法来调用事件 事件触发
eventEmitter.emit('connection');
console.log("log: 程序执行完毕。");

 七、异步控制流

callback形式

回调函数。在理解上,就是函数将任务分配出去,当任务完成之后,然后根据执行结果来进行相应的回调。

function sleep(ms, callback){
    setTimeout(() => {
        callback("sleep执行完成")  //执行完之后,返回‘sleep执行完成’。
    }, ms);
}

sleep(1000, (val) =>{
    console.log(val);
});

多次回调  (多次嵌套会发现代码比较混乱

//第一次调用
sleep(1000, function (val) {
        console.log(val);
        //第二次调用
        sleep(1000, function (val) {
                console.log(val);
                //第三次调用
                sleep(1000, function (val) {
                        console.log(val);
                 });
        });
   
});

Promise对象

我们定义三个json文件

a.json

{
    "next": "b.json",
    "msg": "this is a"
}

b.json

{
    "next": "c.json",
    "msg": "this is b"
}

c.json

{
    "next": null,
    "msg": "this is c"
}

用promise获取文件对象

// 用 promise 获取文件内容
function getFileContent(fileName) {
    const promise = new Promise((resolve, reject) => {
        const fullFileName = path.resolve(__dirname,'file', fileName);
        fs.readFile(fullFileName, (err, data) => {
            if (err) {
                reject(err)
                return
            }
            resolve(
                JSON.parse(data.toString())
            )
        })
    });
    return promise;
}

getFileContent('a.json').then(aData => {
    console.log('a data', aData)
    return getFileContent(aData.next)
}).then(bData => {
    console.log('b data', bData)
    return getFileContent(bData.next)
}).then(cData => {
    console.log('c data', cData)
})

async/await

// 用 promise 获取文件内容
function getFileContent(fileName) {
    const promise = new Promise((resolve, reject) => {
        const fullFileName = path.resolve(__dirname,'file', fileName);
        fs.readFile(fullFileName, (err, data) => {
            if (err) {
                reject(err)
                return
            }
            resolve(
                JSON.parse(data.toString())
            )
        })
    });
    return promise;
}

async function readFileData() {
    // 同步写法
    try {
        const aData = await getFileContent('a.json')
        console.log('a data', aData)
        const bData = await getFileContent(aData.next)
        console.log('b data', bData)
        const cData = await getFileContent(bData.next)
        console.log('c data', cData)
    } catch (err) {
        console.error(err)
    }
}

readFileData();

async function readAData() {
    const aData = await getFileContent('a.json');
    return aData ;
}
async function test() {
    const aData = await readAData();
    console.log(aData);
}
test();

// async await 要点:
// 1. await 后面可以追加 promise 对象,获取 resolve 的值
// 2. await 必须包裹在 async 函数里面
// 3. async 函数执行返回的也是一个 promise 对象
// 4. try-catch 截获 promise 中 reject 的值

八、web应用基础

 1.cookie

Cookie的处理分如下几步

  1. 服务器向客户端发送Cookie
  2. 浏览器将Cookie保存
  3. 之后每次浏览器都会将Cookie发向服务端

HTTP_Parser会将报文字段解析到req.headers上。获取Cookie就是req.headers.cookie上面

解析Cookie也是非常方便的:

//Cookie的格式key=value;key2=value2
var parseCookie = (cookie) => {
   var cookies = {}; 
   if(!cookie){
       return cookies;
   }
   var list = cookie.split(';');
   for (var i = 0; i < list.length; i++) {
       var pair = list[i].split('=');
       cookies[pair[0].trim()] = pair[1];
   }
    return cookies;
}

九、Buffer

Buffer转字符串

buf.toString('UTF-8');

字符串转Buffer

new Buffer(str, [encoding]);

Buffer拼接

Buffer的使用场景中,通常是一段一段的方式进行传输的。下面的方法也是比较常见的读取数据的。


const http = require('http');

const server = http.createServer((req, res) => {
    console.log('req.method)', req.method);
    console.log('content-type', req.headers['Content-Type']);

    if ('POST' === req.method) {
     let postData ="";
     req.on('data', (chunk) => {
         console.log('xiangzaixiansheng---chunk', chunk);
         console.log('xiangzaixiansheng---chunk--string',chunk.toString('UTF-8'));
         postData += chunk;
     });

     req.on('end', () => {
         console.log('xiangzaixiansheng---', postData);
         res.end(postData);
     });

    } else if ('GET' === req.method) {
        res.end('123456789');
    }
});

server.listen(3000);

data事件中读取的chunk数据对象其实为Buffer对象。只不过我们在postData += chunk;的时候相当于

postData = chunk.toString() + postData.toString();执行的。

 如果存在宽字节或者中文数据,可能会出现问题,我们使用下面的拼接方式进行拼接Buffer。

const http = require('http');
const iconv = require('iconv-lite');


const server = http.createServer((req, res) => {

    var chunks = [];
    var size = 0;
    if ('POST' === req.method) {
     let postData ="";
     req.on('data', (chunk) => {
        chunks.push(chunk);
        size += chunk.length;
        console.log('size', size);
     });

     req.on('end', () => {
         //使用Buffer.concat()拼接一个Buffer对象
         var buf = Buffer.concat(chunks, size);
         var str = iconv.decode(buf, 'utf8');
         console.log('xiangzaixiansheng---buf', buf);
         console.log('xiangzaixiansheng---str', str);
         res.end(str);
     });

    } else if ('GET' === req.method) {
        res.end('123456789');
    }
});

server.listen(3000);

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值