node 笔记
- node 不是框架,也不是系统库, 是js适合运行在服务端的运行环境
在Node 中模块有三种:
- 具名的核心模块, 例如: fs、http、os等
- 用户自己编写的文件模块,想对路径必须加 ./ 可以省略后缀名, 想对路径 ./ 不可省略
在Node中, 没有全局作用域,只有模块作用域(外部访问不到内部, 内部也访问不到外部)
引入文件模块语法:
require('./b') 或者 require('./b.js') 文件后缀可以省略
模块之间通信?
使用exports 把需要外部访问的成员放到exports上
require方法有两个作用:
- 加载文件模块并执行里面的代码
- 拿到被加载文件模块导出的接口对象:exports 默认是一个空对象
端口号
ip地址用来定位计算机,端口号用来定位对应的应用程序,
每个应用程序都有对应的端口号, 端口号可以找到对应的应用程序端口号使用范围: 0 - 65535 之间
可以同时开启多个服务, 但是一定要确保不通服务占用的端口号不一致才可以
在服务器默认发送的数据,其实是utf8编码的内容,但是浏览器不知道是utf8编码的内容,浏览器在不知道服务器响应内容编码的情况下会按照当前操作系统默认的编码去解析, 中文操作系统默认是gbk, 解决方法就是正确的告诉浏览器发送的内容是什么编码的
发送html格式的字符串需要告诉浏览器 text/html格式的文本
res.setHeader('Content-Type', 'text/html; charset=utf-8');
ContentType
http://tool.oschina.net
服务端渲染
- 在服务端使用模板
// 在node 中使用art-template 模板引擎
// 1. 安装 sudo npm install art-template
// 2. 在需要使用的文件模块中加载art-template
// var template = require('art-template'); 参数中art-template 就是下载包的名字
// 3. 查文档,使用模板引擎的API
var template = require('art-template');
var ret = template.render('模板字符串 hello {{name}}', {
name: 'Jack'
})
console.log(ret); // 模板字符串 hello Jack
var http = require('http')
var fs = require('fs')
var template = require('art-template')
var server = http.createServer()
var wwwDir = 'D:/Movie/www'
server.on('request', function (req, res) {
var url = req.url
fs.readFile('./template-apache.html', function (err, data) {
if (err) {
return res.end('404 Not Found.')
}
// 1. 如何得到 wwwDir 目录列表中的文件名和目录名
// fs.readdir
// 2. 如何将得到的文件名和目录名替换到 template.html 中
// 2.1 在 template.html 中需要替换的位置预留一个特殊的标记(就像以前使用模板引擎的标记一样)
// 2.2 根据 files 生成需要的 HTML 内容
// 只要你做了这两件事儿,那这个问题就解决了
fs.readdir(wwwDir, function (err, files) {
if (err) {
return res.end('Can not find www dir.')
}
// 这里只需要使用模板引擎解析替换 data 中的模板字符串就可以了
// 数据就是 files
// 然后去你的 template.html 文件中编写你的模板语法就可以了
var htmlStr = template.render(data.toString(), {
title: '哈哈',
files: files
})
// 3. 发送解析替换过后的响应数据
res.end(htmlStr)
})
})
})
server.listen(3000, function () {
console.log('running...')
})
CommonJS
在 Node中的JavaScript还有一个很重要的概念, 模块系统
- 模块作用域
- 使用require方法加载模块
- 使用exports接口对象导出模块中的成员
直接导出不是挂载在exports上, 使用 module.exports = X。
exports和module.exports
exports是module.exports的一个引用
require方法 加载规则
- 优先从缓存中加载
- 核心模块
- 路径形式的文件模块
- 第三方模块
- 判断模块标识(核心模块名、路径、通过npm安装的第三方的)
- 第三方模块: node_modules-》表示名文件-》package.json -> main对应的文件入口 -》main或package.json没有自动找index.js -》index.js没有 找上一级目录中的node_modules-》没有一直找到磁盘根目录,-》没有报错
npm
node package manager
package.json
建议每个项目都要有一个package.json文件(包描述文件)
这个文件可以通过npm init 的方式自动初始化出来 或者npm init -y
npm install 会直接找到package.json中的依赖项全部安装
npm命令行工具
- npm --versin 查看版本
- npm install --global npm 升级
- npm init 初始化package.json
- npm init -y 跳过向导直接生成 package.json
- npm install 安装package.json 中所有的包
- 简写 npm i
- npm install 包名 只下载
- npm install 包名 --save 下载并保持包名到package.json
- npm uninstall 删除, 只删除包
- 简写 npm un
- npm uninstall --save 删除包和依赖信息
- npm un --s 简写
- npm help 查看使用帮助
- npm 命令 --help 查看指定命令帮助
Express
Express官网
示例
let express = require('express');
let app = express();
app.listen(3333, function () {
console.log('starting');
});
app.get('/', function (req, res) {
res.send('hello');
})
// 公开资源 公开public文件下的资源
app.use('/public/ha/', express.static('./public')); // 访问时使用localhost:3333/public/ha/**
app.use(express.static('./public'));
// 访问时使用 localhost:3333/**
//推荐使用
app.use('/public', express.static('./public')); // 访问时使用localhost:3333/public/**
在模块加载中, 相对路径中的./不能省略
文件操作中的相对路径可以省略./, 所有文件操作的api都是异步的
- 文件加载中。
- ./data/a.txt 相对于当前目录
- data/a.txt 相对于当前目录
- /data/a.txt 绝对路径, 想对文件所在磁盘根目录
- c:/data/a.txt 绝对路径
修改完代码自动重启
使用nodemon 工具
sudo npm install --global nodemon
如果报错提示不允许写入文件可以使用sudo npm install nodemon -g --unsafe-perm=true
安装后 使用nodemon app.js
启动项目
在express中配置art-template
art-template官网
- 安装
npm install --save art-template
npm install --save express-art-template
或
sudo npm install --save art-template express-art-template
- 配置
app.engine('html', require('express-art-template'));
- 使用
// express 默认回去views目录中找admin.html
res.render('admin.html', {
name: 'xiaoli'
});
})
- 修改默认的views视图渲染存储目录,可以
app.set('views', 目标路径)
第一个参数固定
在Express中获取post请求的数据
- 使用插件 body-parser
- 安装
sudo npm install --save body-parser
- 引入
let bodyParder = require('body-parser');
- 配置
// 配置body-parser
app.use(bodyParder.urlencoded({extended: false}))
app.use(bodyParder.json());
- 使用
// 1. 获取post请求体数据, 2. 处理, 3. 发送相应 console.log(req.body); // 有了body-parser req中自动存在了body属性 }
MongoDB
参考菜鸟教程
- 可以有多个数据库
- 一个数据库中可以有过个集合(表)
- 一个结合中可以多个文档(表记录)
- 文档结构很灵活,没有任何限制
- MongoDB非常灵活, 不需要像MySQL一样先创建数据库、表、设计表结构
- 在这里只需要插入数据的时候,指定到哪个数据库、哪个集合
- 一切由MongoDB来自动创建表这件事
{
qq:{
users: [
{name: '战三', age : 15},
{name: '战三', age : 15},
{name: '战三', age : 15},
{name: '战三', age : 15},
]
}
}
- 便捷使用第三方库 mongoose
- mongoose官网
Node 操作MySQL
- 第三方库 mysql
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : '',
database : 'user'
});
connection.connect();
let findStr = 'select * from users';
connection.query("INSERT INTO users values (5, '张三', '9999')", function (error, results, fields) {
if (error) throw error;
console.log('The solution is: ', results[0]);
});
connection.end();
Promise
为解决回调嵌套问题,ES6新增API Promise
var fs = require('fs');
var p1 = new Promise(function (resolve, reject) {
fs.readFile('./data/a.txt', 'utf8', function (err, data) {
if (err) {
reject(err);
} else {
resolve(data);
}
})
});
var p2 = new Promise(function (resolve, reject) {
fs.readFile('./data/b.txt', 'utf8', function (err, data) {
if (err) {
reject(err);
} else {
resolve(data);
}
})
});
var p3 = new Promise(function (resolve, reject) {
fs.readFile('./data/c.txt', 'utf8', function (err, data) {
if (err) {
reject(err);
} else {
resolve(data);
}
})
});
p1.then(function (data) { // 此作为p1的 resolve方法
console.log(data);
return p2; // return p2 执行p2的then方法
}, function (err) {
console.log('errrrrrrrr');
}).then(function (data) { // 此作为p2的 resolve方法
console.log(data);
return p3;
}, function (err) {
console.log('errrrrrrrr');
}).then(function (data) { 此作为p3的 resolve方法
console.log(data);
}, function (err) {
console.log('errrrrrrrr');
})
// 顺序输出 aaaa bbbbbb cccccc
- Promise 封装和使用
function pReadFile(filePath) {
return new Promise(function (resolve, reject) {
fs.readFile(filePath, 'utf8', function (err, data) {
if (err) {
reject(err);
} else {
resolve(data);
}
})
})
}
pReadFile('./data/a.txt')
.then(function (data) {
console.log(data);
return pReadFile('./data/b.txt')
})
.then(function (data) {
console.log(data);
}, function (err) {
throw err;
})
mongoose 所有的API都支持Promise
path 路径操作模块
- path.basename
- path.dirname
- path.extname
- path.parse
- path.join
- path.isAbsolute
Node中的其他成员
在每个模块中, 出了 require exports 等模块相关API之外, 还有两个特殊的成员
__direname 动态获取当前文件模所属目录的绝对路径
__filename 动态获取当前文件的绝对路径
-
平常写的 ./ 目录是相对于执行node命令目录的
- 加入目录为 day06/demo/app
- 执行node 可以 node app
- ./ 目录是 demo
- 也可以 node demo/app
- ./ 目录是 day06
require('./js/hah.js') 也有类似问题
在node中相对路径是不可靠的
可以使用 __dirname __filename 把相对路径改为绝对路径 不受node命令所在路径影响
在文件操作中, 建议使用动态获取绝对路径
在模块引入中的模块路径标识 ./想对路径不受影响。
模块中的路径标识和文件操作中的相对路径标识不一样
模块中的路径标识就是相对于当前文件模块, 不受node命令所处路径影响
art-template 中的include 语法 和 extend-block语法
art-template语法
表单同步提交和一步提交
- 以前没有ajax都是同步提交, 同步提交返回信息需要渲染到页面,重新刷新页面
- 异步提交 页面不会刷新, 交互方式更灵活 后端重定向对前端无效
express-session 插件
- 在express环境使用session
Express 中间件
使用中间件
参考