Node.js学习笔记----day01
认真学习,认真记录,每天都要有进步呀!!!
加油叭!!!
一、Node.js的简介
- Node.js是什么
(1)Node.js不是一门语言
(2) Node.js也不是库,也不是框架
(3)Node.js是一个JavaScript运行时的脚本
简单的说 Node.js 就是运行在服务端的 JavaScript。可以解析和执行JS代码,是一个编写网络系统和Web应用程序的平台,围绕事件驱动的非阻塞编程模型构建的。Node.js使用事件驱动,非阻塞I/O模型,轻量、高效,可以完美地处理时时数据,运行在不同的设备上。并且Node.js基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好
- 使用NodeJS的场景:
(1)RESTful API
这是NodeJS最理想的应用场景,可以处理数万条连接,本身没有太多的逻辑,只需要请求API,组织数据进行返回即可。它本质上只是从某个数据库中查找一些值并将它们组成一个响应。由于响应是少量文本,入站请求也是少量的文本,因此流量不高,一台机器甚至也可以处理最繁忙的公司的API需求。
(2)统一Web应用的UI层
目前MVC的架构,在某种意义上来说,Web开发有两个UI层,一个是在浏览器里面我们最终看到的,另一个在server端,负责生成和拼接页面。
不讨论这种架构是好是坏,但是有另外一种实践,面向服务的架构,更好的做前后端的依赖分离。如果所有的关键业务逻辑都封装成REST调用,就意味着在上层只需要考虑如何用这些REST接口构建具体的应用。那些后端程序员们根本不操心具体数据是如何从一个页面传递到另一个页面的,他们也不用管用户数据更新是通过Ajax异步获取的还是通过刷新页面。
(3)大量Ajax请求的应用
例如个性化应用,每个用户看到的页面都不一样,缓存失效,需要在页面加载的时候发起Ajax请求,NodeJS能响应大量的并发请求。总而言之,NodeJS适合运用在高并发、I/O密集、少量业务逻辑的场景。
- Node.js中的JS与浏览器中的JS的区别:
浏览器中的JS:
- EcmaScript
- BOM
- DOM
Node.js中的JS:
- 有EcmaScript
- 没有BOM
- 没有DOM
二、安装Node环境
-
安装
解压文件,一路 Next ,如果想要更改默认路径的话,就得配置一下环境变量
3. 查看Node版本
$ node --version 或者 node -v
三、Hello World
- 创建编辑JavaScript脚本文件
demo.js
console.log("Hello World!");
- 打开终端,定位脚本文件所属目录
- 输入node 文件名,执行对应的文件
注意:文件名不要使用 node.js 来命名(最好不要使用中文)
栗子:
程序执行后,正常的话,就会在终端输出 Hello World!
四、Node操作文件
Node 读取文件
浏览器中的 JavaScript 是没有文件操作的能力的,但是 Node 中的 JavaScript 具有文件操作的能力
- 使用 require 方法加载 fs 核心模块
var fs = require('fs')
解释:
fs 是 file-system 的简写,就是文件系统的意思
在 Node 中如果想要进行文件操作,就必须引入 fs 这个核心模块
在 fs 这个核心模块中,就提供了所有的文件操作相关的 API
例如:fs.readFile 就是用来读取文件的
- 读取文件
fs.readFile(参数一, 参数二)
解释:
参数一:就是要读取的文件路径
参数二:是一个回调函数
- 栗子:
test.txt
你好呀,我是一个test文件。
demo02.js
var fs = require('fs')
fs.readFile('./test.txt', function (error, data) {
console.log(error)
console.log(data)
})
终端打印结果:
如果是读取一个不存在的文件
var fs = require('fs')
fs.readFile('./test1.txt', function (error, data) {
console.log(error)
console.log(data)
})
终端打印结果:
结论:
读取文件成功:
error null
data 数据
读取文件失败:
error 错误对象
data undefined没有数据
注意:
可以看到,终端给我们返回的数据并不是test.txt中我们想要的数据
文件中存储的其实都是二进制数据 0 1
这里为什么看到的不是 0 和 1 呢?原因是二进制转为 16 进制了
但是无论是二进制01还是16进制,人类都不认识
所以我们可以通过 toString 方法把其转为我们能认识的字符
如图:
读取文件及简单的错误处理:
// 在回调函数中利用if语句通过判断 error 来确认是否有错误发生
if (error) {
console.log('读取文件失败了')
} else {
console.log(data.toString())
}
Node写入文件
- 使用 require 方法加载 fs 核心模块
var fs = require('fs')
- 写入文件
fs.writeFile(参数一, 参数二,参数三)
解释:
参数一:文件路径
参数二:文件内容
参数三:回调函数
- 栗子:
demo03.js
var fs = require('fs')
fs.writeFile('./test03.md', '大家好,给大家介绍一下,我是Node.js', function (error) {
if (error) {
console.log('文件写入失败')
} else {
console.log('文件写入成功')
}
})
打印结果:
五、使用Node去搭建一个简单的Web服务器
- 加载 http 核心模块
var http = require('http')
- 使用 http.createServer() 方法创建一个 Web 服务器
var server = http.createServer()
- 服务器要干嘛?
提供服务:对 数据的服务
发请求
接收请求
处理请求
给个反馈(发送响应)
注册 request 请求事件
当客户端请求过来,就会自动触发服务器的 request 请求事件,然后执行第二个参数:回调处理函数
server.on('request', function () {
})
//参数一: 注册request请求
//参数二:回调函数
- 绑定端口号,启动服务器
server.listen(3000, function () {
})
//参数一:端口号
//参数二:回调函数
栗子:
var http = require('http')
var server = http.createServer()
server.on('request', function () {
console.log('收到客户端的请求啦')
})
server.listen(3000, function () {
console.log('服务器响应成功啦')
})
通过 http://127.0.0.1:3000/ 或者是 http://localhost:3000/ 访问
当在地址栏中访问一次
http://localhost:3000/
终端就会打印一次 “收到客户端的请求啦”
每访问一次,服务器就会响应一次
六、发送响应
- 加载 http 核心模块
var http = require('http')
- 使用 http.createServer() 方法创建一个 Web 服务器
var server = http.createServer()
- 服务器要干嘛?
server.on('request', function (request, response) {
})
在 server.on() 的 request 请求事件处理函数中需要接收两个参数:
参数一: Request 请求对象
请求对象可以用来获取客户端的一些请求信息,例如请求路径
获取请求路径的方法 : request.url
参数二:Response 响应对象
响应对象可以用来给客户端发送响应消息
给客户端发送响应数据的方法: response.write
write 可以使用多次,但是最后一定要使用 end 来结束响应,否则客户端会一直等待
结束响应: response.end()
- 绑定端口号,启动服务器
server.listen(3000, function () {
})
//参数一:端口号
//参数二:回调函数
栗子:
demo05.js
var http = require('http')
var server = http.createServer()
server.on('request', function (request, response) {
console.log('收到客户端的请求啦')
console.log('请求的路径是:' + request.url)
response.write('hello')
response.write(' nodejs')
response.end()
// 上面的方式比较麻烦,推荐使用更简单的方式,直接 end 的同时发送响应数据
// res.end('hello nodejs')
})
server.listen(3000, function () {
console.log('服务器启动成功啦')
})
七、根据不同请求路径返回不同数据的简单操作
demo06.js
var http = require('http')
var server = http.createServer()
server.on('request',function(req,res){
console.log('收到客户端请求啦。。。')
var url = req.url
if(url == '/'){
res.end('index page')
}else if(url == '/login'){
res.end('login page')
}else if(url == '/logout'){
res.end('logout page')
}else{
res.end('404 Not Found')
}
})
server.listen(3000,function(){
console.log('服务器启动成功。。。')
})
来吧展示:
八、Node中的核心模块
- os(操作系统)核心模块
os 模块提供了操作系统相关的使用方法
Node.js官方os模块方法中文文档地址
http://nodejs.cn/api/os.html
栗子:
var os = require('os');
//os.hostname() 方法以字符串的形式返回操作系统的主机名。
console.log('主机名'+os.hostname());
//os.cpus() 方法返回一个对象数组,包含每个逻辑 CPU 内核的信息。
console.log('本机CPU'+os.cpus());
//os.platform() 方法返回一个字符串,指定 Node.js 编译时的操作系统平台。
console.log('本机操作系统平台'+os.platform());
//os.type() 方法返回一个字符串, 返回的操作系统的名字。
console.log('本机操作系统:'+os.type())
来吧展示:
- path(路径)核心模块
path 模块提供用于处理文件路径和目录路径的实用工具。
Node.js官方path模块方法中文文档地址:http://nodejs.cn/api/path.html
栗子:
var path = require('path');
var testData = 'D:/node/demo/index.html';
//path.basename() 方法返回 path 的最后一部分,
console.log(path.basename(testData));
//path.dirname() 方法返回 path 的目录名,即除去最后一部分的所有路径
console.log(path.dirname(testData));
//path.extname() 方法返回 path 的扩展名
//从最后一次出现 .(句点)字符到 path 最后一部分的字符串结束。
console.log(path.extname(testData));
//path.parse() 方法会返回一个对象,其属性表示 path 的有效元素。
console.log(path.parse(testData));
//path.isAbsolute() 方法检测 path 是否为绝对路径。
console.log(path.isAbsolute(testData));
来吧展示:
- URL核心模块
url 模块用于处理与解析 URL.
NodeJs官方url模块方法中文文档地址:http://nodejs.cn/api/url.html
https://www.cnblogs.com/smile-xin/p/11614719.html
3.1 url.parse()
var url=require('url');
var data='http://demo.cn?name=千夏&age=18';
console.log(url.parse(data))
console.log(url.parse(data).query)
3.2 url.pathname()
获取url的路径部分
var myURL1 = new URL('https://demo.cn');
console.log(myURL1.pathname);
var myURL2 = new URL('https://demo.cn/abc');
console.log(myURL2.pathname);
var myURL3 = new URL('https://demo.cn/abc/def');
console.log(myURL3.pathname);
var myURL4 = new URL('https://demo.cn/abc/def?name=zs');
console.log(myURL4.pathname);
来吧展示:
设置url的路径部分
var myURL = new URL('https://demo.cn/abc');
myURL.pathname = '/xxx';
console.log(myURL.href);
var myURL2 = new URL('https://demo.cn/abc/def');
myURL2.pathname = '/yyy';
console.log(myURL2.href);
来吧展示:
3.3 url.search()
获取及设置 URL 的序列化查询部分。
var myURL = new URL('https://demo.cn/abc?name=zs&age=18');
console.log(myURL.search);
// 打印 ?name=zs&age=18
myURL.search = 'num=10';
console.log(myURL.href);
// 打印 https://example.org/abc?num=10
来吧展示:
九、 http中的Content-Type
Content-Type
服务器最好把每次响应的数据是什么内容类型都告诉客户端,而且要正确的告诉
不同的资源对应的 Content-Type 是不一样,具体参照:
http://tool.oschina.net/commons
对于文本类型的数据,最好都加上编码,目的是为了防止中文解析乱码问题
通过网络发送文件
发送的并不是文件,本质上来讲发送是文件的内容
当浏览器收到服务器响应内容之后,就会根据你的 Content-Type 进行对应的解析处理
栗子:
var http = require('http')
var server = http.createServer()
server.on('request', function (req, res) {
var url = req.url
if (url === '/plain') {
// text/plain 就是普通文本
res.setHeader('Content-Type', 'text/plain; charset=utf-8')
res.end('hello 文本')
} else if (url === '/html') {
// 如果你发送的是 html 格式的字符串,则也要告诉浏览器我给你发送是 text/html 格式的内容
res.setHeader('Content-Type', 'text/html; charset=utf-8')
res.end('<h3>hello html</h3> <a href="">我是a标签</a>')
}
})
server.listen(3000, function () {
console.log('Server is running...')
})
来吧展示:
根据不同的url地址分别读取html文件与图片的小小栗子:
var http = require('http')
var fs = require('fs')
var server = http.createServer()
server.on('request', function (req, res) {
var url = req.url
if (url === '/') {
// 我们要发送的还是在文件中的内容
fs.readFile('./index.html', function (err, data) {
if (err) {
res.setHeader('Content-Type', 'text/plain; charset=utf-8')
res.end('文件读取失败,请稍后重试!')
} else {
// data 默认是二进制数据,可以通过 .toString 转为咱们能识别的字符串
// res.end() 支持两种数据类型,一种是二进制,一种是字符串
res.setHeader('Content-Type', 'text/html; charset=utf-8')
res.end(data)
}
})
} else if (url === '/img') {
// url:统一资源定位符
// 一个 url 最终其实是要对应到一个资源的
fs.readFile('./img.jpg', function (err, data) {
if (err) {
res.setHeader('Content-Type', 'text/plain; charset=utf-8')
res.end('文件读取失败,请稍后重试!')
} else {
// data 默认是二进制数据,可以通过 .toString 转为咱们能识别的字符串
// res.end() 支持两种数据类型,一种是二进制,一种是字符串
// 图片就不需要指定编码了,因为我们常说的编码一般指的是:字符编码
res.setHeader('Content-Type', 'image/jpeg')
res.end(data)
}
})
}
})
server.listen(3000, function () {
console.log('Server is running...')
})
index.html
<h1>首页</h1>
来吧展示:
十、什么是模块化
十一、加载与导出
- 加载 require ()方法
require 方法有两个作用:
(1) 加载文件模块并执行里面的代码
(2)拿到被加载文件模块导出的接口对象
- 导出
Node中是模块作用域,默认文件中所有的成员只在当前文件模块有效
对于希望可以被其他模块访问的成员,我们就需要把这些公开的成员都挂载到exports
接口中就可以了
在每个文件模块中都提供了一个对象:exports
exports 默认是一个空对象
你要做的就是把所有需要被外部访问的成员挂载到这个 exports 对象中
2.1 导出多个成员
导出多个成员,拿到的就是函数,字符串
exports.age = 123
exports.hi= 'hello'
exports.func = function(){
console.log('aaa')
}
exports.message={
name:'zs'
}
也可以这样来导出多个成员
module.exports = {
add = function(){
return x + y
},
str:'hello'
}
栗子:
a.js
var bExports = require('./b')
console.log(bExports.foo)
//打印 hello
console.log(bExports.add(10, 20))
// 打印 30
console.log(bExports.age)
//打印 18
b.js
var foo = 'aaa'
exports.foo = 'hello'
function add(x, y) {
return x - y
}
exports.add = function (x, y) {
return x + y
}
var age = 18
exports.age = age
2.2 导出单个成员
module.exports = 'hello'
以下情况会覆盖
module.exports = 'hello'
module.exports = function(x,y){
return x + y
}