一. 为什么要学node
- 用户量大
- 程序员必备技能
- 擅长高并发
- 简单
- 可实现功能多
node.js可以解析和执行js代码,不是语言,不是库,不是环境,以前只有浏览器可以解析和执行js代码,也就是说现在的js可以完全脱离浏览器运行
node.js没有BOM DOM 在node这个js执行环境中为javascript中为javascript提供了一些服务器级别的操作API,
- 例如文件读写
- 网络服务的构建
- 网络通讯
- http服务器
- 等处理。。。
node.js具有以下特性
- event-driven事件驱动
- 非阻塞IO模型(异步)
- 轻量和高效
npm是世界上最大的开源库生态系统
绝大多数javascript相关的包都存存放在了npm上,这样做是为了开发人员更方便的去下载使用
npm install jquery
构件与chrome V8引擎
代码只是有特定格式的字符串,引擎可以去执行和解析,
chrome的V8引擎是目前公认执行js最快的引擎
node.js的作者将chrome的v8引擎移植了出来,开发了一个独立的js运行环境
二. node.js基本使用
2.1 文件操作
读取文件
-
使用require方法加载fs核心模块
-
读取文件
第一个参数 要读取的文件路径
第二个参数 回调函数 error data
读取失败 输出error错误对象 data为空
读取成功 返回读取的数据
//fs是file-system的简写,就是文件系统的意思
//在node中如果想要进行稳健操作,就必须引入fs这个核心模块
//1. 使用require方法加载fs核心模块
var fs = require('fs');
fs.readFile('data/app.txt', function(error, data) {
//使用三目运算符做简单的错误处理
error ? console.log('读取错误') : console.log(data.toString());
});
写入文件
-
使用require方法加载fs核心模块
-
写入文件
第一个参数:要写入的文件路径
第二个参数:要写入的文件内容
第三个参数:回调函数
成功:
文件写入成功 error是null
文件写入成功 error就是错误对象
var fs = require('fs');
fs.writeFile('data/write.txt', '今天是学习node.js的第一天', function(error) {
//使用三目运算符做简单的错误处理
error ? console.log('文件写入失败') : console.log('文件写入成功');
});
抛出异常throw error
2.2 创建web服务器
// 使用node创建一个web服务器
// 在node中专门提供了一个核心模块:http
// http这个模块的核心作用就是用于创建编写服务器
//1. 使用require方法 加载http核心模块
var http = require('http');
//2. 使用http.createServer()方法创建一个web服务器
// 返回一个Server实例
var server = http.createServer();
//3. 服务器要干嘛
/*发请求
接收请求
处理请求
发送响应*/
//注册request请求事件
//当客户端发请求过来,就会触发request请求事件,执行回调函数
server.on('request', function(req,res) {
console.log('已经接受到客户端的请求');
});
//4. 绑定端口号,启动服务器
server.listen(8080, function() {
console.log('服务器启动成功,可以通过http://127.0.0.1:8080或者localhost:8080访问');
});
request请求事件,回调函数有两个参数
-
Request请求对象请求对象可以用来获取客户端的一些请求信息 例如请求路径
-
Response响应对象响应对象可以用来给客户端发送响应消息
// 响应对象可以用来给客户端发送响应消息
server.on('request', function(request, response) {
console.log('已经接受到客户端的请求,请求路径是:' + request.url); //获取请求路径
//response响应对象有一个方法write可以用来给客户发送响应数据
//write可以使用多次,但是最后一定要使用end结束响应,否则客户端会一直等待
response.write('hello');
response.write('node.js');
//结束响应
response.end();
}
JSON,parse() 将json对象转换为js对象
JSON.Stringify() 将js对象转换为json字符串
2.3 Node模块化
Node为js提供了很多服务器级别的api,这些api绝大多数都被宝转到了一个具名的核心模块中了。
例如文件操作的 fs模块,http服务构建的 http模块,path路径操作模块,os操作系统信息获取信息模块
如果想要使用核心模块,就必须在使用前先加载相关的模块
var fs = require('fs');
var http = require('http');//require加载模块
在Node.js中 模块有 1. node自带具名的核心模块 2. 用户编写的核心模块
node使用Common JS作为模块化规范
在node中没有全局作用域,只有模块作用域
外部无法访问内部,内部也无法访问外部,不会因为加载模块导致作用域污染
//a.js
console.log('a start');
//可以省略后缀名
//相对路径的./不可以省略 否则报错 去除之后会把它当成核心模块 后缀名可以省略
require('./b.js');
console.log('a end');
//b.js
console.log('b start');
require('./c.js');
console.log('b end');
//c.js
console.log('c文件被加载执行了');
最终执行结果
PS C:\Users\27843\Desktop\node.js学习\源码\09-简单的模块化> node .\a.js
a start
b start
c文件被加载执行了
b end
a end
由于没有模块与模块之间没有作用域拓展,所以我们导出模块使用 exports
require 有两个作用:拿到加载模块并执行里面的代码;拿到被加载文件模块导出的接口对象
每个文件模块里面都提供了一个对象叫做: exports
exports 默认是一个空对象 需要把所有需要外部访问的成员添加到被访问文件exports这个对象中,再由访问文件使用require接收 调用
//a.js
//声明res获取require接受到的exports对象
var res = require('./b');
console.log(res.foo);
console.log(res.add(1, 2));
//b.js
//在exports中添加数据 可以是函数和值
exports.foo = 'loading';
exports.add = function(a, b) {
return a + b;
}
执行结果:
PS C:\Users\27843\Desktop\node.js学习\源码\09-简单的模块化\加载和导出> node .\a.js
loading
3
使用module.export导出属性和方法
实例2:
moduleA
//使用对象解构引入
const { a, b, add } = require('./B')
//直接使用
console.log(a)
console.log(b)
console.log(add(a, b))
moduleB
let a = 10
let b = 20
let add = function (params1, params2) {
return params1 + params2
}
//使用对象增强写法导出属性和方法
module.exports = { a, b, add }
注意点:
module.export只能导出一个对象- 使用多个
module.export导出结果会后者覆盖前者
2.4 ip地址和端口号
- ip地址用来定位计算机
- 端口号用来定位具体应用程序
- 所有需要联网通信的应用程序都会占用一个端口号
- 端口号范围在0-65536(2^16)之间
- 在计算机中有一些默认的端口号,最好不要去使用 比如http服务的80
- 我们在开发中使用一些简单好记的就行了
- 可以同时开启多个服务,但是一定要确保开启了不同的端口号才可以
2.5 发送数据时设置响应头
关于传输中文字符给浏览器时,浏览器显示无法准确显示的问题
在服务端默认发送的数据是utf-8编码的内容,但是浏览器只会按照操作系统默认编码格式去解析,中文操作系统默认编码格式是gbk
在http协议中,content-type就是用来告知对方发送的数据内容是什么类型,使用setHeader方法设置响应头,可以告知浏览器该服务器的编码格式
res.setHeader('Content-Type', 'text/plain;charset=utf-8');
不同类型文件对于content-type是不一样的,我们在传输文件到前端时需要将对应的文件类型添加到相应头中
- Content-Type
- 服务器最好把每次响应的数据是什么内容类型都告诉客户端,而且要正确的告诉
- 不同的资源对应的 Content-Type 是不一样,具体参照:tool.oschina.net/commons
- 对于文本类型的数据,最好都加上编码,目的是为了防止中文解析乱码问题
- 通过网络发送文件
- 发送的并不是文件,本质上来讲发送是文件的内容
- 当浏览器收到服务器响应内容之后,就会根据你的 Content-Type 进行对应的解析处理
2.6 开放public资源
判断是否以public开头,如果是以public开头的url,则直接访问url对应的文件路径下的文件
let url = req.url
if(url.indexOf('/public/')===0){
fs.readFile('.'+url,(error,data){
error? conslole('404'):res.end(data)
})
}
对于views静态资源里的文件也是有效的 所以静态资源里面的文件的url改为
<link rel="stylesheet" href="/public/css/bootstrap.css">
2.7 处理GET请求
url模块
//引入
const url = require('url');
//url.parse方法可以帮我们解析url,第二个参数为true可以把我们得到的url信息转换为对象形式 解析
var ret = url.parse('http://localhost:3000/pinglun?name=%E5%B0%8F%E9%A3%9E&message=12312312312312', true);
//使用
console.log(ret);
console.log(ret.query);
运行结果
Url {
protocol: 'http:',
slashes: true,
auth: null,
host: 'localhost:3000',
port: '3000',
hostname: 'localhost',
hash: null,
search: '?name=%E5%B0%8F%E9%A3%9E&message=12312312312312',
//重要 GET请求的请求体
query: [Object: null prototype] { name: '小飞', message: '12312312312312' },
//重要 pathname===req.url
pathname: '/pinglun',
path: '/pinglun?name=%E5%B0%8F%E9%A3%9E&message=12312312312312',
href: 'http://localhost:3000/pinglun?name=%E5%B0%8F%E9%A3%9E&message=12312312312312'
}
[Object: null prototype] { name: '小飞', message: '12312312312312' }
由于GET请求会将请求内容放到url后面,我们使用url模块可以解析得到请求内容
//引入url模块
const url = require('url');
//创建实例接收parse的解析结果 并将其转换为对象形式
var pathObj = url.parse('需要解析的连接',true);
//从pathObj中取出请求体
pathObj.query;
取出请求体之后,我们就可以对请求体进行操作
2.8 浏览器重定向
http状态码
301永久重定向
302临时重定向
res.statusCode = 302;
res.setHeader('Location','重定向路径');
res.end();
三. node后端渲染
node后端渲染就是使用fs文件读取模块读取并解析html格式文件
//使用url模块解析浏览器请求地址
var pathObj = url.parse(req.url, true);
//拿到解析后的文件路径
var pathname = pathObj.pathname;
//判断文件路径,依据文件路径解析现有html文件
if (pathname === '/') {
fs.readFile('./views/index.html', 'utf8', (error, data) => {
if (error) {
return console.log('404 not found');
}
var ret = template.render(data, {
comments: comments
})
res.end(ret);
})
}
后端渲染利于SEO优化
五 node.js连接mysql数据库
5.1 不使用数据库连接池
//引入MySQL引擎
const mysql = require('mysql')
//配置MySQL连接信息
const connection = mysql.createConnection({
host: 'localhost',
port: 3309,
user: 'root',
password: '123456',
database: 'library'
})
//建立连接
connection.connect()
// 操作MySQL 处理操作结果
connection.query(option.mysqlStatement, (error, result) => {
if (error) throw error
if (result) console.log(result)
})
//关闭连接
connection.end()
5.2 使用数据库连接池
// 引入数据库引擎
const mysql = require('mysql')
// 创建一个数据库连接池
const pool = mysql.createPool({
host: 'localhost',
port: 3309,
database: 'library',
user: 'root',
password: '123456'
})
// 从连接池中获取一个连接
pool.getConnection((err, conn) => {
if (err) {
console.log('和mysql数据库建立连接失败')
} else {
console.log('和mysql数据库连接成功')
conn.query('select * from readers', (err2, res) => {
if (err2) {
console.log('查询数据库失败')
} else {
console.log(res)
pool.end()
}
})
}
})