目录
一、http
//原生模块
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学习
- 注册一个账户 --> [post] --> http://localhost:8080/register
- 注册成功的情况下跳转到登录界面进行登录 --> [post] --> http://localhost:8080/login
- 登录成功进行获取用户信息 --> [get] --> http://localhost:8080/user
- 同时可以获取博客信息 --> [get] --> http://localhost:8080/blogs
- 如何访问不存在的路由则抛出错误信息。
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);
五、网络编程
状态码
1XX | 2XX | 3XX | 4XX | 5XX |
---|---|---|---|---|
信息性状态码 | 成功状态码 | 重定向 | 客户端错误状态码 | 服务端错误状态码 |
少见 | 200 OK | 301 永久性重定向 | 400 请求报文语法错误 | 500服务器请求错误 |
204 响应报文不含实体的主体部分 | 302 临时性重定向(负载均衡) | 401发送的请求需要有通过 HTTP 认证的认证信息 307 和302含义相同 | 503 服务器暂时处于超负载或正在停机维护,无法处理请求 | |
206 范围请求 | 303 资源存在着另一个 URL,应使用 GET 方法定向获取资源 | 403 对请求资源的访问被服务器拒绝 | ||
304 客户端已经执行了GET,但文件未变化。 | 404 服务器上没有找到请求的资源 |
Node内置的模块,对应的网络通信方式
模块 | 服务 |
---|---|
net | TCP |
dgram | UDP |
http | HTTP |
https | HTTPS |
构建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的处理分如下几步
- 服务器向客户端发送Cookie
- 浏览器将Cookie保存
- 之后每次浏览器都会将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);