nodejs简介
nodejs什么是?
为什么学nodejs?
- 了解前后端交互流程
- 能够自己写api接口
- 防止甩锅,明确前后端职责范围
- 为了更高的薪资
nodejs的特点
- 单线程:
- 单线程在程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行。
- 多线程的好处:可以提高CPU的利用率。在多线程程序中,一个线程必须等待的时候,CPU可以运行其它的线程而不是等待,这样就大大提高了程序的效率。
- 非阻塞I/O(input/output)
- 网络请求、数据库处理、文件的读写。。。
- 事件驱动
环境配置
nodejs安装
- Node.js是一个让JavaScript运行在服务器端的开发平台,所以必须首先在本机安装Node.js环境
- 下载地址
- 官网术语解释
- LTS 版本:Long-term Support 版本,长期支持版,即稳定版。
- Current 版本:Latest Features 版本,最新版本,新特性会在该版本中最先加入。
- 在cmd中,输入 node -v 就能够查看版本号
- 同时,nodejs 也内置了npm,通过 npm -v 查看版本号
NPM是包管理工具,包的结构使您能够轻松跟踪依赖项和版本
。- npm官网
- 生成 package.json 配置文件
- npm init 自定义配置
- npm init -y 跳过所有提问,生成默认配置文件
nvm
- 通过 nvm 安装管理多个nodejs版本
- nvm常用命令
- nvm install version 安装version版本的nodejs,例如:nvm install 8.16.0
- nvm uninstall version 卸载version版本的nodejs,例如:nvm uninstall 8.16.0
- nvm list 显示所有安装的nodejs版本
- nvm list available 显示可以安装的nodejs的版本
- nvm use version 使用指定的nodejs版本,例如:nvm use 8.16.0
NPM淘宝镜像
- 查看npm源地址
- npm config get registry 默认源:https://registry.npmjs.org/
- 通过cnpm使用
- npm install -g cnpm --registry=https://registry.npm.taobao.org
- 通过npm使用
- npm config set registry https://registry.npm.taobao.org 推荐
运行程序
js运行环境
- 浏览器(基本语法、dom、bom、ajax请求…)
- 服务器(基本语法、操作本地文件、操作数据库…)
限制语言能力的不是语言本身,而是语言的运行环境.
运行nodejs程序
- 在命令行中执行node指令并回车,进行node的交互式环境(REPL环境)
- 把javascript代码写在后缀为.js的文件中,命令行执行:node xx.js
- 按下 ctrl + c 退出当前执行程序
node.js是服务端的程序,写的js语句,都将运行在服务器上
.- node.js没有根目录、没有web容器的概念!
nodemon
- nodemon会实时监听js代码,发现有修改后自动重启服务器
- 安装:npm install --global nodemon
- 之前使用:node xxx.js 改成:nodemon xxx.js
模块化
- 内置模块
- 第三方模块
- 自定义模块
commonjs规范
node应用由各种包各种模块组成
,采用的commonjs模块规范- commonjs加载模块是
同步
的,模块加载的顺序,按照其在代码中出现的顺序 - require 方法用于加载模块文件,相当于读入并执行一个js文件
- module.exports 属性表示当前模块对外
输出的接口
,让其他文件加载该模块
http模块
- http 模块 可以用于创建http服务器与http客户端
- 创建http服务器
- 服务器:一台电脑,安装服务器软件,通过ip地址和端口号访问
htpp://localhost:80 -> 127.0.0.1var http = require('http');
加载http模块var server = http.createServer();
创建http服务- server.on(‘request’, callback); request事件用于监听来自客户端的请求,callback:回调函数。
- server.listen(port, host, callback); 启动http服务,监听3000端口
- 注意:
- 在监听request事件中,最后一定要res.end()结束响应。
- 浏览器显示·
中文可能是乱码·
,需设置响应头告诉浏览器显示时所使用的编码,要在res.end()之前设置响应头、状态码、响应内容类型及编码
res.setHeader("Content-Type","text/plain;charset=utf-8");
res.setHeader("Content-Type","text/html;charset=utf-8");
res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'});
- Content-Type:用于定义用户的浏览器如何处理将要加载的数据.
- text/html 表示响应内容为html的形式,浏览器对响应内容按html解析.
- text/css 表示响应内容为css的形式,浏览器对响应内容按css解析.
- text/plain 表示响应内容为纯文本的形式,浏览器不会对其进行其它处理.
- application/json 表示响应内容为序列化后的 JSON 字符串.
- 创建http客户端
- http.get()
- http.request()
req->request请求对象
res->response响应对象
nodejs没有根目录,没有web容器的概念!!!!!
// 引入模块
const http = require('http')
// 创建http服务
let server = http.createServer()
// 监听server的request事件,有用户请求进来时触发request事件
server.on('request',(req,res)=>{
// req->request请求对象
// res->response响应对象
// console.log(req.url) // path
if (req.url === '/favicon.ico') {
return false
}
console.log('有用户请求进来了。。。')
// 设置响应头信息(告诉浏览器响应内容类型--纯文本,字符集为utf-8)
res.setHeader('Content-Type','text/plain;charset=utf-8')
// 响应给前端的内容
res.end('欢迎光临~~~123') // 结束响应
})
// 监听端口号,启动服务
// server.listen(port,host,callback)
server.listen('3000','10.36.136.59',()=>{
console.log('------------server start------------')
})
fs 模块
- fs模块提供了用于与文件系统进行交互的API
- CURD(Create Update Read Del)
- fs.readFile(file[, options], callback) 读文件
参数1:要读取的文件路径,必填。
参数2:读取文件时的选项,比如:文件编码utf8。选填。
参数3:文件读取完毕后的回调函数,必填。
- fs.writeFile(file, data[, options], callback) 写文件
参数1:要写入的文件路径,必填。
参数2:要写入的数据,必填。
参数3:写入文件时的选项,比如:文件编码。选填。
参数4:文件写入完毕后的回调函数,必填。
writeFile写入文件是先把文件内容清空再写入
如果要追加写入的话可以使用appendFile函数
- fs.unlink() 删除文件
- fs.mkdir() 创建文件夹
- fs.readdir() 读取文件夹
- fs.rmdir() 删除文件夹(只能删除空文件夹)
- fs.rename() 文件重命名
- fs.stat() 获得文件信息
stats.isFile()
stats.isDirectory()
// 同步读取文件,在关键位置捕获错误
try{
var data = fs.readdirSync('./')
} catch (err){
console.log(err)
}
console.log(data)
// 异步读取文件
fs.readdir('./',(err,data)=>{
console.log(data)
})
// 引入模块
const fs = require('fs')
// fs.readFile 异步
// fs.readFileSync 同步
// 异步读取文件
// console.log('111111111111')
// fs.readFile('./test.txt',(err,data)=>{
// // fs.readFile('./test.txt','utf8',(err,data)=>{
// // 错误的回调优先,err默认值为null,如果有错err是一个错误对象
// if (err) {// 有错
// console.log(err)
// console.log('读取失败')
// } else {// 没错
// // console.log(data) // 默认Buffer二进制数据流
// console.log(data.toString()) // 转成字符串
// }
// })
// console.log('222222222222')
// 同步读取文件,在关键位置捕获错误 try {} catch(){}
// console.log('111111111111')
// try {// 把容易出错的代码放这里面执行
// var data = fs.readFileSync('./test1.txt','utf8')
// } catch (err){
// console.log(err)
// }
// console.log(data)
// console.log('222222222222')
// 异步写文件(覆盖写入),如果当前文件不存在则创建此文件
// fs.writeFile('./test.txt','今天发生了一件大事',(err)=>{
// if (err) {
// console.log('写入失败');
// } else {
// console.log('写入成功');
// }
// })
// 异步写文件(追加写入),如果当前文件不存在则创建此文件
// let data = '123456789'
// fs.appendFile('./test.txt',data,(err)=>{
// if (err) {
// console.log('写入失败');
// } else {
// console.log('写入成功');
// }
// })
// 删除文件
// fs.unlink('./demo.html',(err)=>{
// if (err) {
// console.log('删除失败');
// } else {
// console.log('删除成功');
// }
// })
// 创建文件夹
// fs.mkdir('./hehe',(err)=>{
// if (err) {
// console.log('创建失败');
// } else {
// console.log('创建成功');
// }
// })
// 读取文件夹
// fs.readdir('./hehe',(err,data)=>{
// if (err) {
// console.log('读取失败');
// } else {
// console.log(data);// [ 'haha', 'hehe.html', 'index.js' ]
// }
// })
// 判断是文件还是文件夹
// fs.stat('./test.txt',(err,stats)=>{
// if (err) {
// console.log('获取文件信息失败');
// } else {
// console.log( stats.isFile() )// true 代表这个是文件
// console.log( stats.isDirectory() )// true 代表这个是文件夹
// }
// })
// 删除文件夹
// fs.rmdir('./tao',(err)=>{
// if (err) {
// console.log('删除失败');
// } else {
// console.log('删除成功');
// }
// })
// 修改文件夹名字
fs.rename('./hehe','xixi',(err)=>{
if (err) {
console.log('修改失败');
} else {
console.log('修改成功');
}
})
url 模块
- url 模块 用于处理与解析 URL
- url叫统一资源定位符
- url.parse()方法 将url字符串转成对象
- url.format()方法 将url对象转成字符串
let urlStr = 'https://www.baidu.com/ss/abc?wd=directory&spt=123&issp=888#head';
let urlObj = url.parse( urlStr ); // 默认false,query为字符串
let urlObj = url.parse(urlStr,true); // 设置true,query为对象
// 引入模块
const url = require('url')
let urlStr = 'https://www.baidu.com/ss/abc?wd=directory&spt=123&issp=888#head'
// 将url字符串转成对象
// let urlObj = url.parse(urlStr,false) // 第二个参数默认为false,query部分为字符串
let urlObj = url.parse(urlStr,true) // 第二个参数默认为true,query部分为对象
console.log( urlObj );
let url_o = {
protocol: 'https:',
slashes: true,
auth: null,
host: 'www.baidu.com',
port: null,
hostname: 'www.baidu.com',
hash: '#head',
search: '?wd=directory&spt=123&issp=888',
// query: 'wd=directory&spt=123&issp=888',
query: { wd: 'directory', spt: '123', issp: '888' },
pathname: '/ss/abc',
path: '/ss/abc?wd=directory&spt=123&issp=888',
href: 'https://www.baidu.com/ss/abc?wd=directory&spt=123&issp=888#head'
}
// 将url对象转成字符串
let url_s = url.format(url_o)
console.log(url_s);// https://www.baidu.com/ss/abc?wd=directory&spt=123&issp=888#head
path 模块
- path模块提供用于
·处理文件路径和目录路径·
的实用工具 - path模块的默认操作会根据Node.js程序运行的操作系统而有所不同.
- path.join(path1[, path2]…) 将多个路径规范化拼接,返回拼接后的路径.
- path.resolve([…paths]) 将一系列路径解析成
绝对路径
,从右到左解析.
如果没有参数调用,返回当前工作路径. - path.basename(path[, ext]) 返回路径的最后部分(文件名)
path目标路径,ext要截掉的内容. - path.dirname(path) 与basename相对,返回除最后一部分的前面部分路径.
const path = require('path')
// 从右到左拼接
// join拼接返回相对路径
// console.log( path.join('/user','login','index.html') );// '\user\login\index.html'
// console.log( path.join('user','/login','./index.html') );// 'user\login\index.html'
// console.log( path.join('user','../login','./index.html') );// 'login\index.html'
// resolve拼接返回绝对路径
// console.log( path.resolve('/user','login','index.html') );
// D:\user\login\index.html
// console.log( path.resolve('user','/login','./index.html') );
// D:\login\index.html
// console.log( path.resolve('user','../login','./index.html') );
// D:\phpstudy_pro\WWW\test\2005\node\day01\login\index.html
let path1 = 'node/day01/login/index.html'
// 返回路径的最后一部分(文件名)
// console.log( path.basename(path1) );// 'index.html'
// console.log( path.basename(path1,'.html') );// 'index'
// 返回除了path.basename之外的内容
console.log( path.dirname(path1) );// 'node/day01/login'
querystring 模块
- querystring模块提供用于
解析和格式化URL查询字符串
的实用工具 - 将query字符串转成对象
let str = ‘wd=directory&spt=123&issp=888’;
let obj = qs.parse( str ); // 默认等价于 qs.parse( str, ‘&’, ‘=’ );
console.log( obj ); // { wd: ‘directory’, spt: ‘123’, issp: ‘888’ } - 将对象转成query字符串
let obj = { wd: ‘directory’, spt: ‘123’, issp: ‘888’ };
let str = qs.stringify( obj );
console.log( str ); // ‘wd=directory&spt=123&issp=888’ query字符串编码
let str = ‘msg=你好&pw=123 456’;
let res = qs.escape( str );
console.log( res ); // msg%3D%E4%BD%A0%E5%A5…query字符串解码
res = qs.unescape( res );
console.log( res ); // ‘msg=你好&pw=123 456’
// querystring模块
const qs = require('querystring')
let obj1 = { wd: 'directory', spt: '123', issp: '888' }
// 封装一个方法把它转成 'wd=directory&spt=123&issp=888'
// function stringify(obj){
// let str = ''
// for (let key in obj){
// str += key+'='+obj[key]+'&'
// }
// str = str.substring(0,str.length-1)
// return str
// }
// console.log( stringify(obj1) );
// 将对象转成query字符串
// console.log( qs.stringify(obj1) );// 'wd=directory&spt=123&issp=888'
// 等价于
// 第一个参数是要转换的对象
// 第二个参数是键值对之间的分隔符
// 第三个参数是键和值之间的分隔符
// console.log( qs.stringify(obj1,'&','=') );// 'wd=directory&spt=123&issp=888'
// 自定义字符串格式
// console.log( qs.stringify(obj1,'@','-') );// 'wd-directory@spt-123@issp-888'
// query字符串转成对象
// let str = 'wd=directory&spt=123&issp=888'
// console.log( qs.parse(str) );// { wd: 'directory', spt: '123', issp: '888' }
// 等价于
// console.log( qs.parse(str,'&','=') );// { wd: 'directory', spt: '123', issp: '888' }
// let str2 = 'a:1,b:2,c:3'
// console.log( qs.parse(str2,',',':') );// { a: '1', b: '2', c: '3' }
// 编码后的字符串
let str3 = 'wd=%E7%BE%8E%E5%A5%B3&rsv_spt=1&issp=1'
// 解码
// console.log( qs.unescape(str3) );// 'wd=美女&rsv_spt=1&issp=1'
let str4 = 'wd=美女&rsv_spt=1&issp=1'
// 编码
// console.log( qs.escape(str4) );// 'wd%3D%E7%BE%8E%E5%A5%B3%26rsv_spt%3D1%26issp%3D1'
// 原生js也有编码和解码方法
console.log( escape('你好=123%') );
console.log( unescape('%u4F60%u597D%3D123%25') );
全局变量
-
__dirname 表示当前执行的脚本所在目录的绝对路径
- 如:D:\phpstudy_pro\WWW\test\GP03\day33
-
__filename 表示当前执行的脚本文件的绝对路径
- 如:D:\phpstudy_pro\WWW\test\GP03\day33\test.js
-
process是一个全局进程模块
-
console.log( process.env ) 当前的环境信息
-
console.log( process.argv[2] ) 获取输入的命令
// 当前执行脚本的绝对目录
// console.log( __dirname );
// D:\phpstudy_pro\WWW\test\2005\node\day01
// 当前执行脚本的绝对路径
// console.log( __filename );
// D:\phpstudy_pro\WWW\test\2005\node\day01\11-global.js
// console.log( process );
// console.log( process.env );// 当前执行的环境变量
console.log( process.argv[2] );// 用户在命令行输入的自定义命令
// gulp dev -> node gulpfile.js dev
Error对象
- let err = new Error(‘发送错误了’);
- console.log(err); 这只是一个错误对象,不会终止代码执行
- throw err; 抛出错误,会终止代码执行
- console.log(‘这里不会执行’)
// 创建错误对象,不会影响后面的程序执行
let err = new Error('出错啦')
console.log(err) // 打印错误对象,不会影响后面的程序执行
throw new Error('抛出错误') // 抛出一个错误,会影响后面的程序执行
console.log('程序4')
// 加载模块
const http = require('http')
const fs = require('fs')
const url = require('url')
// 创建http服务,并监听用户请求
http.createServer((req,res)=>{
// console.log( req.url );// path部分
// console.log( url.parse(req.url) );// {...}
let pn = url.parse(req.url).pathname
if (pn === '/favicon.ico') {
return
}
if (pn === '/') {
fs.readFile('./index.html','utf8',(err,data)=>{
if (err) {
// 设置响应头信息,状态码,响应内容类型,字符集
res.writeHead(200,{'Content-Type':'text/plain;charset=utf-8'})
res.end('无法访问首页页面')
} else {
// 设置响应头信息,状态码,响应内容类型,字符集
res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'})
res.end(data)
}
})
} else if (pn === '/hehe') {
fs.readFile('./hehe.html','utf8',(err,data)=>{
if (err) {
// 设置响应头信息,状态码,响应内容类型,字符集
res.writeHead(200,{'Content-Type':'text/plain;charset=utf-8'})
res.end('无法访问hehe页面')
} else {
// 设置响应头信息,状态码,响应内容类型,字符集
res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'})
res.end(data)
}
})
} else if (pn === '/haha') {
fs.readFile('./haha.html','utf8',(err,data)=>{
if (err) {
// 设置响应头信息,状态码,响应内容类型,字符集
res.writeHead(200,{'Content-Type':'text/plain;charset=utf-8'})
res.end('无法访问haha页面')
} else {
// 设置响应头信息,状态码,响应内容类型,字符集
res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'})
res.end(data)
}
})
} else if (pn === '/c1.jpg') {
fs.readFile('./c1.jpg',(err,data)=>{
if (err) {
// 设置响应头信息,状态码,响应内容类型,字符集
res.writeHead(200,{'Content-Type':'text/plain;charset=utf-8'})
res.end('找不到图片')
} else {
// 设置响应头信息,状态码,响应内容类型,字符集
res.writeHead(200,{'Content-Type':'image/jpeg;charset=utf-8'})
res.end(data)
}
})
}else if (pn === '/index.css') {
fs.readFile('./index.css',(err,data)=>{
if (err) {
// 设置响应头信息,状态码,响应内容类型,字符集
res.writeHead(200,{'Content-Type':'text/plain;charset=utf-8'})
res.end('找不到样式')
} else {
// 设置响应头信息,状态码,响应内容类型,字符集
res.writeHead(200,{'Content-Type':'text/css;charset=utf-8'})
res.end(data)
}
})
} else {
// 设置响应头信息,状态码,响应内容类型,字符集
res.writeHead(200,{'Content-Type':'text/plain;charset=utf-8'})
res.end('404找不到页面')
}
}).listen(3003,()=>{
console.log( '-----------server start-----------' )
})
// 用户访问:http://localhost:3003