node.js入门基础
内容:
1.node.js介绍
2.node.js内置常用模块
3.node.js数据交互
一、node.js介绍
(1)node.js特点
与其他语言相比,有以下优点:
- 对象、语法和JavaScript一模一样,易于前端使用
- 相比PHP、Java、python,性能还可以
- 前后端配合方便
- 非阻塞、异步的交互
当然,也有缺点:比如说库支持不如Java丰富,和js一样是单线程单进程
(2)node.js安装
下载对应你系统的Node.js版本:https://nodejs.org/en/download/,选安装目录进行安装即可
安装完毕测试如下:
(3)node.js用处
- 服务器 - 小型后台系统、中间层
- 做工具(测试、构建、抓取) - grunt、gulp、WebPack
(4)运行node
创建一个node文件夹,然后在文件夹下写入1.js:
let a = 12;
let b = 5; console.log(a+b)
然后在命令行中进入node目录下运行该文件:node 1.js 注:node运行文件:node xxx.js
运行结果如下:
二、node.js内置常用模块
1.断言——assert
const assert = require("assert") function sum(a, b){
// assert(判断, "xxx") 判断为假输出后面的信息
assert(arguments.length==2, "必须传两个参数")
assert(typeof a == 'number', "第一个参数必须是数字")
assert(typeof b == 'number', "第二个参数必须是数字") return a+b
} console.log(sum(2, 5))
// 执行下面人任意一句将报错:
// console.log(sum(2, '1'))
// console.log(sum(3))
2.Buffer和File System模块
- buffer:曾经是node中的模块,后来融入到node本身之中了,处理二进制
- file system:处理文件(读写文件)
file system使用实例:
const fs = require("fs") // 读取文件
fs.readFile('1.txt', function(err, data){
if(err){
console.log("有错!");
} else {
console.log(data);
console.log(data.toString());
} }) // 写文件
fs.writeFile('2.txt', 'xxx', function(err){
if (err) {
console.log(err);
} else {
console.log("成功!");
}
})
注意:图片不要将二进制转成字符串,这样做会导致图片格式丢失
获取文件详细信息:
const fs = require('fs') fs.stat('1.txt', function (err, stat) {
if(err){
console.log('获取文件信息失败')
} else{
console.log(stat) // detail info
console.log(stat.mtime.toGMTString()) // 修改时间
}
})
Buffer基础使用:
let a = new Buffer('abc');
let b = new Buffer('ddd');
console.log(a, b)
// <Buffer 61 62 63> <Buffer 64 64 64> let c = Buffer.concat([a, b]);
console.log(c);
// <Buffer 61 62 63 64 64 64>
Buffer数据操作:
// 查找
let a=new Buffer('abccc-=-dddder-=-qwerqwer');
console.log(a.indexOf('-=-')); // 截取
let b=new Buffer('abccc-=-dddder-=-qwerqwer');
console.log(b.slice(0, 5).toString()); // 切分 --> 目前buffer自带的操作中没有可以直接用的split
let c=new Buffer('abccc-=-dddder-=-qwerqwer'); Buffer.prototype.split=Buffer.prototype.split||function (c){ // 如果buffer有split就用buffer自带的split,没有就用下面的函数
let arr=[]; let cur=0;
let n=0;
while((n=this.indexOf(c, cur))!==-1){
arr.push(this.slice(cur, n));
cur=n+c.length;
} arr.push(this.slice(cur)); return arr;
}; let arr=c.split('-=-');
console.log(arr);
console.log(arr.map(buffer=>buffer.toString()));
3.C++ Addons - 用C语言/C++写插件给node用
4.多进程
理论上JavaScript是单进程单线程的,可以通过以下模块实现多进程:
- Child Processes
- Cluster
- Process
注:node中没有多线程的直接实现(为了考虑安全性、应用性)
(1)进程与线程
- 进程:进程拥有独立的执行空间和存储空间
- 线程:同一个进程内的所有线程共享一套空间、代码
- 多进程:成本高(慢)、安全(进程间隔离)、进程间通信麻烦、写代码简单、PHP、node
- 多线程:成本低(快)、不安全(线程间共享)、线程间通信简单、写代码复杂、Java、C
- 多进程:慢、简单、安全
- 多线程:快、复杂、脆弱
(2)进程之间的通信方法
- 管道
- 共享内存
- socket
(3)详细用法
详细用法见:https://www.cnblogs.com/wyb666/p/9704056.html
5.Crypto——散列、签名
crypto模块提供了md5、sha算法,主要用来进行加密(实质上是散列)、签名
普通加密:
const crypto = require('crypto') let obj = crypto.createHash('sha1')
// 或者用md5加密:
// let obj = crypto.createHash('md5') obj.update('123456') console.log(obj.digest('hex')) # 以16进制输出数据
二次加密并加盐:
const crypto = require('crypto') function md5(str){
let obj = crypto.createHash('md5')
obj.update(str) return obj.digest('hex')
} // 二级加密并加盐
console.log(md5(md5('123456') + 'asdfghjklzxcvbnm,./' ))
6.http
- HTTP/HTTPS
- HTTP/2
下面是用http模块搭建简单服务器的大致过程:
最简单的服务器:
const http = require("http") let server = http.createServer(function(req, res){
// 路由处理
switch(req.url){
case '/aaa':
res.write('abc');
break;
case '/bbb':
res.write('dddd');
break;
case '/1.html':
res.write('<html><head></head><body>sdfasfasf</body></html>');
break;
}
res.end()
}); // 监听
server.listen(8080)
前后端代码分离的服务器(前端代码存在www文件夹下):
const http=require('http');
const fs=require('fs'); let server=http.createServer(function(req, res){
fs.readFile(`www${req.url}`, function(err, data){
if(err){
res.write('404'); // 404页面
}else{
res.write(data);
}
res.end();
});
}); server.listen(8080);
注意:fs.readFile是一个异步操作,必须将res.end()放在readFile内,如果放在readFile外面会导致以下错误:
这个错误是因为程序不会等readFile执行完就会执行后面的end,因此要将end放在readFile内才会在读完文件后执行end
7.OS和Path
- OS:系统相关
- Path:处理路径
const os=require('os');
const path=require('path'); // 输出CPU信息:
console.log(os.cpus()); // 路径相关:
let str='/var/local/www/aaa/1.png';
//dirname -> 文件夹路径
//basename -> 文件名
//extname -> 拓展名
console.log(path.dirname(str)); // /var/local/www/aaa
console.log(path.basename(str)); // 1.png
console.log(path.extname(str)); // .png
8.Events事件队列
(1)机制原理
Nodejs的大部分核心API都是基于异步事件驱动设计的,所有可以分发事件的对象都是EventEmitter类的实例。
大家知道,由于nodejs是单线程运行的,所以nodejs需要借助事件轮询,不断去查询事件队列中的事件消息,然后执行该事件对应的回调函数,有点类似windows的消息映射机制
(2)使用实例
const Event = require("events").EventEmitter let ev = new Event() // 1、监听(接受)
ev.on('msg', function(a, b, c){
console.log('收到了msg事件', a, b, c);
}) // 2、派发(发送)
ev.emit('msg', 12, 5, 98)
(3)注意
大多数时候我们不会直接使用 EventEmitter,而是在对象中继承它。包括 fs、net、 http 在内的,只要是支持事件响应的核心模块都是 EventEmitter 的子类
- 具有某个实体功能的对象实现事件符合语义, 事件的监听和发射应该是一个对象的方法
- JavaScript 的对象机制是基于原型的,支持 部分多重继承,继承 EventEmitter 不会打乱对象原有的继承关系
9.Query Strings和URL
(1)Query Strings
Query Strings:查询字符串,url中的?之后的字符串即为Query Strings
比如www.xxx.com/find?s=k&wd=123中的查询字符串就是 s=k&wd=123
querystring实例:
const querystring = require("querystring") // url: www.xxx.com/find?s=k&wd=123
let obj = querystring.parse("s=k&wd=123") console.log(obj)
// 解析结果: { s: 'k', wd: '123' }
(2)URL
url模块和querystring模块不同之处:url模块解析整个url,而querystring只能解析url中问号之后的字符串
实例:
const url = require("url") let obj = url.parse("www.xxx.com/find?s=k&wd=123") console.log(obj)
/*
输出结果:
Url {
protocol: null,
slashes: null,
auth: null,
host: null,
port: null,
hostname: null,
hash: null,
search: '?s=k&wd=123',
query: 's=k&wd=123',
pathname: 'www.xxx.com/find',
path: 'www.xxx.com/find?s=k&wd=123',
href: 'www.xxx.com/find?s=k&wd=123'
}
*/
注意:也可以像下面一样指定将query也一并解析
const url = require("url") let obj = url.parse("www.xxx.com/find?s=k&wd=123", true) console.log(obj)
/*
输出结果:
Url {
protocol: null,
slashes: null,
auth: null,
host: null,
port: null,
hostname: null,
hash: null,
search: '?s=k&wd=123',
query: { s: 'k', wd: '123' },
pathname: 'www.xxx.com/find',
path: 'www.xxx.com/find?s=k&wd=123',
href: 'www.xxx.com/find?s=k&wd=123'
}
*/
10.网络相关模块
- TCP-稳定 -> Net
- UDP-快 -> UDP/Datagram
- DNS -> 域名解析相关
- Domain -> 域名相关
DNS解析实例:
const dns = require("dns") dns.resolve("baidu.com", function(err, res){
if(err){
console.log("解析失败")
} else {
console.log(res)
} }) // 结果: [ '220.181.57.216', '123.125.115.110' ]
11.流操作——Stream
(1)什么是流
连续数据都是流:比如说视频流、网络流、文件流、语音流
(2)Stream具体操作
读取写入文件:
const fs = require('fs') let rs = fs.createReadStream('1.txt') // 读取流
let ws = fs.createWriteStream('2.txt') // 写入流 rs.pipe(ws) // 异常处理
rs.on('error', function (error) {
console.log('读取失败!')
}) // 读取完成 及 写入完成
rs.on('end', function () {
console.log('读取完成!')
}) ws.on('finish', function () {
console.log('写入完成!')
})
12.TLS/SSL
用于加密、安全
13.ZLIB
用于压缩 - gz压缩
zlib模块使用实例:
const zlib = require('zlib')
const fs = require('fs') let rs = fs.createReadStream('jQuery.js')
let ws = fs.createWriteStream('jQuery.js.gz') let gz = zlib.createGzip() rs.pipe(gz).pipe(ws) // 异常处理
rs.on('error', function (error) {
console.log('读取失败!')
}) // 读取完成 及 写入完成
rs.on('end', function () {
console.log('读取完成!')
}) ws.on('finish', function () {
console.log('写入完成!')
})
三、node.js数据交互
web服务器三大任务:返回文件(html、css、图片等)、数据交互(get、post)、数据库,下面的部分将围绕返回文件及数据交互展开
1.返回文件
返回文件可以使用node.js中的fs模块,实例如下:
const fs = require("fs") fs.readFile('1.txt', function(err, data){
if(err){
console.log("有错!");
} else {
console.log(data); // 二进制 Buffer -> 可以直接把这样的数据返回给前端(图片只能返回二进制,返回字符串将使图片失效)
console.log(data.toString());
} })
2.数据交互 - get和post和文件上传
- get数据:url里面、小于32K
- post数据:作为body、比较大
- file数据:form表单的处理、后端的处理
(1)设置header
- setHeader() --> 一般使用这种来设置header(键值对)
- writeHeader()
- write()
简单设置header:
const http=require('http');
const fs=require('fs'); let server=http.createServer(function(req, res){
fs.readFile(`www${req.url}`, function(err, data){
if(err){
// 返回404
res.writeHeader(404); // header
res.write('Not Found'); // body
}else{
res.write(data);
}
res.end();
});
}); server.listen(8080);
(2)get数据处理
get表单:
<form action="http://localhost:8080/aaa" method="get">
用户:<input type="text" name="user" /><br>
密码:<input type="password" name="pass" /><br>
<input type="submit" value="提交">
</form>
后端node:
const http=require('http')
const url=require('url') let server=http.createServer(function(req, res){
let {pathname, query} = url.parse(req.url, true)
console.log(pathname) // -> /xxx的形式
console.log(query) // -> { user: 'xxx', pass: 'xxx' }的形式 res.end()
}) server.listen(8080)
(3)post数据处理
post表单(注意get和post请求可以同时提交):
<form action="http://localhost:8080/aaa?id=12&a=55" method="post">
用户:<input type="text" name="user" /><br>
密码:<input type="password" name="pass" /><br>
<input type="submit" value="提交">
</form>
后端node:
const http=require('http')
const querystring=require('querystring') let server=http.createServer(function(req, res){
let str='' // 有一个段到达了
req.on('data', function(data){
str+=data
}) // 结束了
req.on('end', function(){
let post=querystring.parse(str)
console.log(str)
console.log(post)
}) res.end()
}) server.listen(8080)
注意:url和querystring的不同之处:
1 // url解析整个url
2 url.parse("www.xxx.com/aaa/bbb?a=12&b=5")
3 url.parse("/aaa/bbb?a=12&b=5")
4 // 另外加上true表示进一步解析query参数(不加就默认不进一步解析query):
5 url.parse("/aaa/bbb?a=12&b=5", true)
6 ->
7 {
8 、、、
9 "query": {a: 12, b: 5}
10 、、、
11 }
12
13 // querystring解析数据
14 querystring.parse("a=12&b=5")
(4)get和post数据一块处理
前端还是使用前面的get表单和post表单
后端node:
const http=require('http');
const url=require('url');
const querystring=require('querystring'); let server=http.createServer((req, res)=>{
// GET
let {pathname, query}=url.parse(req.url, true); // POST
let str='';
req.on('data', function(data){
str+=data;
});
req.on('end', function(){
let post=querystring.parse(str); console.log(pathname, query, post);
}); res.end()
}); server.listen(8080);
注意:在一个表单中可以get请求可以和post请求同时发
(5)文件上传
前端代码:
<form action="" method="post" enctype="multipart/form-data">
<input type="file" name="upload-file">
<input type="submit" value="上传文件">
</form> 注意:
上传文件时表单中的enctype="multipart/form-data"必须要写
input(file)必须要有name
后端可以使用fs中的readFile和writeFile实现(读取完上传的文件后保存)
这样做有弊端:
- 只能等到所有数据都到达了才开始处理
- readFile先把所有数据全读到内存中,然后回调:
- 1.极其占用内存
- 2.资源利用极其不充分
更好的方法:使用流,实例见后面的文件上传实例
3.数据交互实例 - 登陆注册简单实现
(1)基本原理
// GET数据 -> 在url中
let {pathname, query} = url.parse(req.url, true) // 请求的地址及?之后的参数 // POST数据 -> 在body里 比较大
let str = ''
req.on('data', function(data){
str += data // post提交的数据
}) req.end('end', function(err){
let post = querystring.parse(str) // 解析提交的数据(字符串->对象)
})
(2)前端代码
<!-- author: wyb -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登陆</title>
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
</head>
<body> 用户名: <input type="text" id="user"> <br>
密码: <input type="password" id="pass"> <br>
<input type="button" value="注册" id="btn1">
<input type="button" value="登陆" id="btn2"> <script>
/*
// 前后端接口:
用户注册:
/reg?user=xxx&pass=xxx
=>{error: 0, msg: '说明'} 用户登陆:
/login?user=xxx&pass=xxx
=>{error: 0, msg: '说明'}
*/
$(function () {
// 注册
$('#btn1').click(function () {
$.ajax({
url: '/reg',
data: {user: $('#user').val(), pass: $('#pass').val()},
dataType: 'json',
success(data){
if(data.error){
alert("错了: " + data.msg)
} else {
alert("注册成功")
}
},
error(){
alert("错了")
}
})
}) // 登陆
$('#btn2').click(function () {
$.ajax({
url: '/login',
data: {user: $('#user').val(), pass: $('#pass').val()},
dataType: 'json',
success(data){
if(data.error){
alert("错了: " + data.msg)
} else {
alert("登陆成功")
}
},
error(){
alert("错了")
}
})
})
})
</script> </body>
</html>
(3)后端代码(node)
const http = require('http');
const url = require('url');
const querystring = require('querystring');
const fs = require('fs'); /*
// 前后端接口:
用户注册:
/reg?user=xxx&pass=xxx
=>{error: 0, msg: '说明'} 用户登陆:
/login?user=xxx&pass=xxx
=>{error: 0, msg: '说明'}
*/ // users在内存中保存用户登陆信息
let users = {
// 'xxx': '123456',
// 'wyb': '654321'
}; let server = http.createServer(function(req, res) {
// GET
let {pathname, query} = url.parse(req.url, true); // POST
let str = '';
req.on('data', function (data) {
str += data;
}); req.on('end', function () {
let post = querystring.parse(str);
let {user, pass} = query switch (pathname) {
// 注册
case '/reg':
if (!user) {
res.write('{"error": 1, "msg": "user is required!"}')
} else if (!pass) {
res.write('{"error": 1, "msg": "pass is required!"}')
} else if (!/^\w{3,32}$/.test(user)) {
res.write('{"error": 1, "msg": "invalid username!"}')
} else if (!/^\w{6,32}$/.test(pass)) {
res.write('{"error": 1, "msg": "invalid password!"}')
} else if (/^['"|]$/.test(pass)) {
res.write('{"error": 1, "msg": "invalid password!"}')
} else if (users[user]) {
res.write('{"error": 1, "msg": "username already exists!"}')
} else {
users[user] = pass
res.write('{"error": 0, "msg": "register success!"}')
} res.end()
break
// 登陆
case '/login':
if (!user) {
res.write('{"error": 1, "msg": "user is required!"}')
} else if (!pass) {
res.write('{"error": 1, "msg": "pass is required!"}')
} else if (!users[user]) {
res.write('{"error": 1, "msg": "no this user!"}')
} else if (users[user]!==pass) {
res.write('{"error": 1, "msg": "username or password is incorrect!"}')
} else {
res.write('{"error": 0, "msg": "login success!"}')
} res.end()
break
default:
fs.readFile(`www${pathname}`, function (err, data) {
if (err) {
res.writeHead(404)
res.write("Not Found!")
} else {
res.write(data)
} res.end()
})
} }); }); server.listen(8080);
4.文件上传实例 - 用流实现
直接看这里:https://www.cnblogs.com/wyb666/p/9694481.html
node.js入门基础的更多相关文章
- Node.js 入门:Express + Mongoose 基础使用
前言 Express 是基于 Node.js 平台的 web 应用开发框架,在学习了 Node.js 的基础知识后,可以使用 Express 框架来搭建一个 web 应用,实现对数据库的增删查改. 数 ...
- 极简 Node.js 入门 - Node.js 是什么、性能有优势?
极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...
- 极简 Node.js 入门 - 2.1 Path
极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...
- 极简 Node.js 入门 - 4.4 可写流
极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...
- 极简 Node.js 入门 - 5.2 url & querystring
极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...
- node.js学习(二)--Node.js控制台(REPL)&&Node.js的基础和语法
1.1.2 Node.js控制台(REPL) Node.js也有自己的虚拟的运行环境:REPL. 我们可以使用它来执行任何的Node.js或者javascript代码.还可以引入模块和使用文件系统. ...
- Node.js系列基础学习----安装,实现Hello World, REPL
Node.js基础学习 简介 简单的说 Node.js 就是运行在服务端的 JavaScript.Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台.Node.js是一 ...
- Node.js 入门手册:那些最流行的 Web 开发框架
这篇文章与大家分享最流行的 Node.js Web 开发框架.Node 是一个服务器端 JavaScript 解释器,它将改变服务器应该如何工作的概念.它的目标是帮助程序员构建高度可伸缩的应用程序,编 ...
- 【特别推荐】Node.js 入门教程和学习资源汇总
这篇文章与大家分享一批很有用的 Node.js 入门教程和学习资源.Node 是一个服务器端的 JavaScript 解释器,它将改变服务器应该如何工作的概念.它的目标是帮助程序员构建高度可伸缩的应用 ...
随机推荐
- ElasticSearch(十):springboot集成ElasticSearch集群完成数据的增,删,改
前言 之前介绍了使用devTools进行索引库数据的crud,这里使用的是java程序,使用中间件activeMQ进行数据库和索引库数据的同步.主要是用来完成对数据库的修改来完成对索引库的同步. 正文 ...
- 来自官方的一些dbt 最佳实践
限制对原始数据的依赖性 您的项目将取决于存储在数据库中的原始数据.我们建议制作所谓的“基本模型”,以最大限度地减少对原始数据表的依赖性.在此约定中,基本模型可以具有以下职责: 仅选择与当前分析相关的字 ...
- Selenium(ThoughtWorks公司开发的web自动化测试工具)
Selenium也是一个用于Web应用程序测试的工具.Selenium测试直接运行在浏览器中,就像真正的用户在操作一样.支持的浏览器包括IE(7.8.9).Mozilla Firefox.Mozill ...
- bat删除系统默认共享
在我们的系统中,有很多默认的共享是开启的,可以设置一个bat文件在每次开机的时候把共享删除. net share c$ /del net share d$ /del net share e$ /del ...
- redis-benchmark压力测试
redis-benchmark是redis官方提供的压测工具,安装好redis后,默认安装.使用简便. 语法: Usage: redis-benchmark [-h <host>] [-p ...
- 写了一篇关于 FastAdmin 插件路由的分析文章
写了一篇关于 FastAdmin 插件路由的分析文章 插件路由演示 ThinkPHP 的路由就像是整个应用的调度室,让你的应用 url 更友好,而且让应用更安全,不会让真实的地址暴露出去. 了解过 L ...
- css学习日记
相对偏移 指定left top等属性就能够够完美控制一个元素的位置 如: position:relative; left:2px; 今天遇到一个很好玩的问题,当两个并排浮动框,当一个框的长度太大时就会 ...
- ERROR 1130 (HY000): Host '192.168.20.165' is not allowed to connect to this MySQL server
问题 远程连接mysql时遇到如下问题: ERROR 1130 (HY000): Host '192.168.20.165' is not allowed to connect to this MyS ...
- golang之配置环境
从https://golang.org/dl/下载相关包,直接解压 目录大概这样 golang ├── go └── mods 配置环境变量 vim ~/.profile(debian需要勾选shel ...
- java 静态导入