1.NodeJs的优势
- 擅长处理高并发
- 简单易学,适合前端实现后端功能
- 实现的功能多
2.HTTP模块
http模块可以用来创建一个服务,vscode安装了node snippets插件后可使用提示工具快捷生成一个服务(node-http-server)
// 引入http模块
const http = require('http');
// 创建一个服务,在createServer方法中传入一个函数(可用箭头函数),函数中有两个参数
http.createServer(function (request, response) {
//设置 HTTP 头部,状态码是 200,文件类型是 html,字符集是 utf8
response.writeHead(200,{"Content-Type":"text/html;charset=UTF-8"});
// 可通过write方法返回响应体内容
res.write("<head> <meta charset='UTF-8'></head>"); //解决乱码
// 结束响应end()方法必须调用,可传入一个字符串的参数展示在页面上,否则页面虽然会展示内容,但是图标的刷新按钮会一直旋转
res.end();
// 对该服务的端口进行监听
}).listen(8888);
3.URL模块
可通过request.url获取url,然后使用url模块进行解析
const url=require('url'); // 引入url模块
parse方法能将url解析,第一个参数为要解析的url地址,第二个可选参数为true表示将url解析后的query(储存url中?后面的参数,以name=xx&age=xx方式储存)转换为对象的key:value形式,便于使用
var getValue=url.parse(api,true).query;
url.format(urlObject): parse方法的逆操作
url.resolve(from,to): 添加或替换地址
4.supervisor
注意每当修改完代码后需要ctrl+c停止服务,再重新启动服务。这样会很麻烦,此时可以全局安装supervisor代替node启动服务
npm install superviosr -g
5.CommonJs和模块化
- commonjs是一个模块化的标准,nodejs是commonjs模块化的实现
模块分为nodejs内置的核心模块(http、url、fs)和用户定义的自定义模块 - 模块化就是把公共的功能抽离出来形成一个js文件作为模块,定义如此js文件的时候内部的属性方法有两种暴露的方法
- export:
适合逐个暴露
- module.exports:
适合将方法属性合成一个对象暴露出来
- 导入模块
如果模块是在node_modules中导入的路径可以省略node_modules以及前面的内容,如果模块是以index.js命名,路径可以省略index.js,如
const axios=require('./node_modules/axios/index');
可以省略为
const axios=require('axios');
若是非index.js命名也可以在该文件当前目录下在cmd命令行界面运行npm init --yes
创建package.json文件后实现同样功能 - 在nodejs中除了核心模块外其他第三方模块都是以包组成,通过包对一组具有相互依赖关系的模块进行统一管理。符合CommonJs规范的包目录一般包含以下文件:
·package.json :包描述文件。
·bin :用于存放可执行二进制文件的目录
· lib :用于存放 JavaScript 代码的目录
·doc :用于存放文档的目录。
npm的常用命令
- npm installl ModuleName
后面可以添加的后缀为:
- –save:向package.json文件中添加模块的版本配置信息
- –dev:将模块的配置信息放在package.json文件的devDependencies中,默认放在dependencies中
- –g:全局安装
- npm install ModuleName@1.8.0 指定版本安装
- npm init 或者npm init -yes在当前目录下创建package.json文件
6.package.json文件
dependencies:生产时依赖
devDependencies:开发时依赖
"dependencies": {
"ejs": "^2.3.4",
"express": "^4.13.3",
"formidable": "^1.0.17"
}
^表示第一位版本号不变,后面两位取最新的
~表示前两位不变,最后一个取最新
*表示全部取最新
如果不加前缀表示指定版本
7.fs模块
fs模块是nodejs的核心模块,主要是进行文件操作的,引入fs模块const fs = require('fs')
;
fs模块有9个方法:
- fs.stat 检测是文件还是目录
fs.stat('./html',(err,data)=>{
if(err){
console.log(err);
return;
}
console.log(`是文件:${data.isFile()}`);
console.log(`是目录:${data.isDirectory()}`);
})
- fs.mkdir 创建目录,其有三个参数
path 将创建的目录路径
mode 目录权限(读写权限),默认777,可选
callback 回调,传递异常参数err
fs.mkdir('./css',(err)=>{
if(err){
console.log(err);
return;
}
console.log('创建成功');
})
- fs.writeFile 创建写入文件
fs.writeFile('./html/index.html','你好nodejs',(err)=>{
if(err){
console.log(err);
return;
}
console.log('创建写入文件成功');
})
- fs.appendFile 追加文件
fs.appendFile('./css/base.css','body{color:red}',(err)=>{
if(err){
console.log(err);
return;
}
console.log('appendFile 成功');
})
- fs.readFile 读取文件
fs.readFile('./html/index.html',(err,data)=>{
if(err){
console.log(err);
return;
}
console.log(data);
console.log(data.toString()); //把Buffer 转化成string类型
})
- fs.readdir读取目录
fs.readdir('./html',(err,data)=>{
if(err){
console.log(err);
return;
}
console.log(data);
})
- fs.rename 重命名 移动文件
fs.rename('./css/aaa.css','./css/index.css',(err)=>{
if(err){
console.log(err);
return;
}
console.log('重命名成功');
})
- fs.rmdir 删除目录
fs.rmdir('./aaaa',(err)=>{
if(err){
console.log(err);
return;
}
console.log('删除目录成功');
})
- fs.unlink 删除文件
fs.unlink('./aaaa/index.html',(err)=>{
if(err){
console.log(err);
return;
}
console.log('删除文件成功');
})
- fs.createReadStream 从文件流中读取数据
var fileReadStream = fs.createReadStream('data.json')
let count=0;
var str='';
fileReadStream.on('data', (chunk) => {
console.log(`${ ++count } 接收到:${chunk.length}`);
str+=chunk
})
fileReadStream.on('end', () => { console.log('--- 结束 ---');
console.log(count);
console.log(str);
})
fileReadStream.on('error', (error) => {
console.log(error)
})
- fs.createWriteStream 写入文件
var data = '我是从数据库获取的数据,我要保存起来';
// 创建一个可以写入的流,写入到文件 output.txt 中
var writerStream = fs.createWriteStream('output.txt');
// 使用 utf8 编码写入数据
writerStream.write(data,'UTF8');
// 标记文件末尾
writerStream.end();
// 处理流事件 --> finish 事件
writerStream.on('finish', function() {
/*finish - 所有数据已被写入到底层系统时触发。*/
console.log("写入完成。");
});
writerStream.on('error', function(err){
console.log(err.stack);
});
console.log("程序执行完毕");
- 管道流,用于处理大文件的赋值时,主要还是通过读写流来实现
// 创建一个可读流
var readerStream = fs.createReadStream('input.txt');
// 创建一个可写流
var writerStream = fs.createWriteStream('output.txt');
// 管道读写操作
// 读取 input.txt 文件内容,并将内容写入到 output.txt 文件中
readerStream.pipe(writerStream);
console.log("程序执行完毕");
8.创建简单web服务思路
- 通过http模块创建服务
http.createServer(function (req, res) {}).listen(3000);
- 通过请求地址,req获取url,然后通过核心模块url处理url获取地址
let pathname=url.parse(req.url).pathname;
- 设置默认地址
pathname=pathname=='/'?'/index.html':pathname;
- 获取请求文件的拓展名,用于设置响应头的响应文件类型,不同的资源Content-Type是不同的,例如text/html 表示 HTML格式,text/css 表示css格式
let extname=path.extname(pathname);
- 通过fs模块读取文件
if(pathname!='/favicon.ico'){
fs.readFile('./static'+pathname,async (err,data)=>{
if(err){
res.writeHead(404, {'Content-Type': 'text/html;charset="utf-8"'});
res.end('404这个页面不存在');
}
let mime=await common.getFileMime(extname);
res.writeHead(200, {'Content-Type': ''+mime+';charset="utf-8"'});
res.end(data);
})
}
完整示例
const http = require('http');
const fs = require('fs');
const common=require('./module/common.js'); // 自定义模块
const path=require('path');
const url=require('url');
http.createServer(function (req, res) {
//1、获取地址
let pathname=url.parse(req.url).pathname;
pathname=pathname=='/'?'/index.html':pathname; // 设置默认访问路径
let extname=path.extname(pathname); // 获取路径扩展名
//2、通过fs模块读取文件
if(pathname!='/favicon.ico'){
fs.readFile('./static'+pathname,async (err,data)=>{
if(err){
res.writeHead(404, {'Content-Type': 'text/html;charset="utf-8"'});
res.end('404这个页面不存在');
}
let mime=await common.getFileMime(extname);
res.writeHead(200, {'Content-Type': ''+mime+';charset="utf-8"'});
res.end(data);
})
}
}).listen(3000);
console.log('Server running at http://127.0.0.1:3000/');
自定义模块(设置响应的文本类型)
const fs=require('fs');
exports.getMime = function (extname) {
switch (extname) {
case '.html':
return 'text/html';
case '.css':
return 'text/css';
case '.js':
return 'text/javascript';
default:
return 'text/html';
}
}
exports.getFileMime = function (extname) {
return new Promise((resolve,reject)=>{
fs.readFile('./data/mime.json',(err,data)=>{
if(err){
console.log(err);
reject(err);
return;
}
let mimeObj=JSON.parse(data.toString());
// console.log(mimeObj[extname]);
resolve(mimeObj[extname]);
})
})
}
9.格式转换
buffer类型->string:xxx.toString()
string–>对象: JSON.parse(xxx)
10.简单了解ejs
ejs是实现后端渲染的实用工具,可以将从数据库和文件中读取到的数据显示到html页面中,其主要的方法和标签如下:
ejs.renderFile(filename, data, options, function(err, str){
// str => Rendered HTML string
});
其中filename为html文件的路径,data为需要传入的数据(以对象形式传入),options为一些参数(可基本忽略),str为插入数据后的html文件内容,可直接传入前端渲染。
- <% %>:流程控制标签,可写一些js语句
- <%= %>输出标签(原文输出 HTML 标签),可以对变量进行输出
11.get和post传值
- 获取get传值的方法:
var urlinfo=url.parse(req.url,true); // 加了true之后会将参数转换成对象形式
urlinfo.query; - 获取post传值的方法:
post传值是以流的形式传输,需要用监听on方法将数据拼接
req.on(‘data’, function (postDataChunk) {
postData += postDataChunk;
});
监听传值完毕后对数据进行处理
req.on(‘end’, function () {
try {
postData = JSON.parse(postData);
} catch (e) { }
req.query = postData;
console.log(querystring.parse(postData));
});
简单封装类似于Express的方法
- module下创建一个route文件,文件中定义一个默认暴露的函数app(定义对象也可以,不过因为创建http服务的时候需要传入一个回调函数)
http.createServer(function (req, res) { }).listen(3000);
- 为app函数设置一个get方法如下,其中G为定义在全局的一个对象:
app.get = function (str,callback) {G[str]=cb;}
假设调用app.get(’/login’, (req,res) => console.log(‘此处执行登录方法’); )就相当于在route文件G中定义了一个login = (req,res) => console.log(‘此处执行登录方法’);的方法(路径中的‘/’可用splice方法分割掉) - 通用可以在app函数中设置post方法
- 在app.js文件中引入route默认暴露的函数app,创建httpserver的时候将其传入,并在app中配置路由
http.createServer(app).listen(3000);
app.get('/login',function(req,res){
res.writeHead(200, { 'Content-Type': 'text/html;charset="utf-8"' });
res.end('执行登录操作');
})
app.get('/news',function(req,res){
res.writeHead(200, { 'Content-Type': 'text/html;charset="utf-8"' });
res.end('新闻页面');
})