1、Node服务器开发
1.1、Node环境搭建
1.1.1、Node下载
下载地址: http://nodejs.cn/download/
将Node安装到指定的目录下,例如: c:\nodejs,(可以在任何盘符下创建,不建议放C盘)
1.1.2、NPM修改默认全局安装路径
步骤1:
执行快捷键 win+r
,弹出运行窗口,输入 cmd
打开命令提示符窗口,执行命令:
npm config ls
上面命令是查看npm的默认全局安装路径,主要查看 prefix
和 cache
这两项配置,我们修改NPM全局安装路径,就是改的这两个配置。
步骤2:
在c:\nodejs(Node的安装目录下),创建两个文件夹,分别是:
C:\nodejs\node_gobal
C:\nodejs\node_cache
如下图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hzCuXQoM-1608041834674)(./img/1602210896992.png)]
步骤3:
创建好上面两个文件夹后,执行下面命令:
npm config set prefix "C:\nodejs\node_gobal"
npm config set cache "C:\nodejs\node_cache"
注意:执行上面两个命令,什么都不会提示。
上面两个命令执行完成后,再次执行:
步骤5:
安装上述过程操作完成后,全部点击确定。
可以尝试全局安装一个模块,看该模块是否下载到了 c:\nodejs\node_gobal 目录下。
例如:安装cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org
1.1.3、编写Hello World
在指定的目录下创建一个 .js
的文件,例如: d:\demo\index.js,在js文件中编辑以下代码
1.2、Node模块
1.2.1、Node模块的引入方法
var xxx = require('xxx')
1.2.2、文件模块
读取文件案例:
var fs = require('fs')
//异步读取的文件
fs.readFile("./app.txt", "utf-8", function(err, data){
if(err) {
return console.log(err);
}
console.log('异步读取的内容:',data.toString());
});
//同步读取文件
var data = fs.readFileSync("./app.txt","utf-8");
console.log('同步读取的内容:',data.toString());
写入文件案例:
var fs = require('fs')
fs.writeFile("./app.txt", "this is new data", "utf-8", function(err){
if(err){
console.log('文件写入错误',err)
return
}
console.log('文件写入成')
});
1.2.3、http模块
代码案例:
var http = require('http')
var connect = http.createServer(function(req,res){
res.end('hello world !')
});
connect.listen(3000,function(){
console.log('服务器启动成功');
})
1.2.4、path模块
var path = require('path')
// 连接路径
var url = path.join('/demo','hello','abc','haha');
console.log(url);
// 获取文件的绝对路径
var url2 = path.resolve('demo.js')
console.log(url2);
// 获取文件的扩展名
var name = path.extname('demo.js');
console.log(name);
1.2.5、自定义模块
例如:封装一个获取日期和时间的模块
mydate.js
// 获取日期的函数
function getDate(i){
var d = new Date()
if(i == 1){
return `${d.getFullYear()}-${d.getMonth()+1}-${d.getDate()}`
} else if(i == 2){
return `${d.getFullYear()}/${d.getMonth()+1}/${d.getDate()}`
} else if(i == 3){
return `${d.getFullYear()}年${d.getMonth()+1}月${d.getDate()}日`
} else {
return `${d.getFullYear()}-${d.getMonth()+1}-${d.getDate()}`
}
}
// 获取具体时间的函数
function getTime(){
var d = new Date();
return `${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}`
}
module.exports = {
getDate,
getTime
}
main.js中使用自定义模块
var d = require('./mydate')
console.log(d.getDate(3));
console.log(d.getTime());
1.3、Node服务器搭建
处理中文乱码问题:
var http = require('http')
var connect = http.createServer(function(req,res){
//设置响应头,可以返回html代码,设置编码格式为utf-8,解决中文乱码问题
res.setHeader("Content-Type","text/html;charset=utf-8");
res.end('访问成功')
});
connect.listen(3000,function(){
console.log('服务器启动成功');
})
响应HTML代码:
var http = require('http')
var connect = http.createServer(function(req,res){
//设置响应头,可以返回html代码,设置编码格式为utf-8,解决中文乱码问题
res.setHeader("Content-Type","text/html;charset=utf-8");
var htmlStr = `
<table border='1' width="300px" align="center">
<tr>
<th>姓名</th>
<th>年龄</th>
</tr>
<tr>
<td>张三</td>
<td>20</td>
</tr>
</table>
`
res.write(htmlStr);
res.end();
});
connect.listen(3000,function(){
console.log('服务器启动成功');
})
响应HTML静态文件:
var http = require('http');
var fs = require('fs');
var connect = http.createServer(function(req,res){
//设置响应头,可以返回html代码,设置编码格式为utf-8,解决中文乱码问题
res.setHeader("Content-Type","text/html;charset=utf-8");
var data = fs.readFileSync("./main.html", "utf-8");
res.write(data.toString());
res.end();
});
connect.listen(3000,function(){
console.log('服务器启动成功');
})
1.4、处理请求
判断请求类型:
var http = require('http');
var fs = require('fs');
var connect = http.createServer(function(req,res){
//设置响应头,可以返回html代码,设置编码格式为utf-8,解决中文乱码问题
res.setHeader("Content-Type","text/html;charset=utf-8");
//判断请求类型
if (req.method == 'GET') {
console.log('get请求');
} else if(req.method == 'POST'){
console.log('post请求');
}
res.end();
});
connect.listen(3000,function(){
console.log('服务器启动成功');
})
接收GET请求参数:
var http = require('http');
var fs = require('fs');
var url = require('url');
var connect = http.createServer(function(req,res){
// 阻止获取title中的图标
if(req.url === '/favicon.ico') return
//设置响应头,可以返回html代码,设置编码格式为utf-8,解决中文乱码问题
res.setHeader("Content-Type","text/html;charset=utf-8");
if(req.method == 'GET'){
var params = url.parse(req.url,true).query
console.log(params.name);
console.log(params.pwd);
}
res.end();
});
connect.listen(3000,function(){
console.log('服务器启动成功');
})
接收POST请求参数:
var http = require('http');
var fs = require('fs');
var url = require('url');
var querystring = require('querystring');
var connect = http.createServer(function(req,res){
// 阻止获取title中的图标
if(req.url === '/favicon.ico') return
//设置响应头,可以返回html代码,设置编码格式为utf-8,解决中文乱码问题
res.setHeader("Content-Type","text/html;charset=utf-8");
if(req.method == 'POST'){
var str = "";
req.on('data',function(data){
str += data
})
req.on('end',function(){
var params = querystring.parse(str)
console.log(params.name);
console.log(params.pwd);
})
}
res.end();
});
connect.listen(3000,function(){
console.log('服务器启动成功');
})
处理路由:
var http = require('http');
var fs = require('fs');
var url = require('url');
var querystring = require('querystring');
var connect = http.createServer(function(req,res){
// 阻止获取title中的图标
if(req.url === '/favicon.ico') return
//设置响应头,可以返回html代码,设置编码格式为utf-8,解决中文乱码问题
res.setHeader("Content-Type","text/html;charset=utf-8");
//获取路由
var router = url.parse(req.url,true).pathname;
if(router == '/admin/add'){
console.log('添加');
}else if(router == '/admin/del'){
console.log('删除');
}
res.end();
});
connect.listen(3000,function(){
console.log('服务器启动成功');
})
1.5、Express框架的使用
1.5.1、项目初始化
常用命令:
创建项目:
# 创建项目
express myapp
# 进入项目
cd myapp
安装依赖:
# 初始化依赖
cnpm i
# 安装ejs
cnpm i ejs --save
# 安装数据库
cnpm i mongoose --save
# 安装express-session
cnpm i express-session --save
修改 app.js 中的模板引擎为 ejs:
app.set('view engine', 'ejs');
修改 package.json 文件中的启动命令:
"scripts": {
"start": "nodemon ./bin/www"
}
删除 views 目录下的所有默认的 jade
文件,创建 index.ejs
文件
启动项目:
npm start
1.5.2、Express项目结构
public -- 静态资源托管目录
bin --
www 项目配置文件,启动时调用
routes -- 路由文件
views -- 视图模板引擎
app.js -- 入口文件
package.json -- 项目描述文档
node_modules -- 项目的所有依赖目录
2、MongoDB数据库
2.1、数据库的安装与使用
自己看教程
2.2、增删改查案例
链接数据库
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/logindemo',{useNewUrlParser:true})
.then(()=>{
console.log('数据库连接成功');
})
.catch(err=>{
console.log('数据库连接失败',err);
})
var userSchema = new mongoose.Schema({
username: String,
pwd: String
})
var User = mongoose.model('users',userSchema)
添加数据
User.create({要添加的数据}).then(rel=>{
// rel为添加成功的对象
})
修改数据
User.updateOne({条件},{要修改的内容}).then(rel=>{
// rel为修改结果对象
})
删除数据
User.findOneAndDelete({删除条件}).then(rel=>{
// rel为被删除的对象
})
查询单个对象
User.findOne({条件}).then(rel=>{
// rel为查询出来的对象
})
查询所有对象
User.find({条件}).then(rel=>{
// rel为查询出来的所有对象数组
})
条件查询
//匹配大于 小于
User.find({age: {$gt: 20, $lt: 50}}).then(result => console.log(result))
//匹配包含
User.find({hobbies: {$in: ['敲代码']}}).then(result => console.log(result))
//选择要查询的字段
User.find().select('name email').then(result => console.log(result))
//将数据按照年龄进行排序,1为升序,-1为降序
User.find().sort({age: 1}).then(result => console.log(result))
//skip 跳过多少条数据 limit 限制查询数量
User.find().skip(2).limit(2).then(result => console.log(result))
//查询总记录数
User.find().count().then(result=> console.log(result))
2.3、登录注册案例
2.3.1、用户注册
前台页面代码,/views/reg.ejs
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<form action="/users/reg/info" method="post">
<div>
用户名:<input type="text" name="username" autocomplete="off">
</div>
<div>
密 码:<input type="password" name="pwd" autocomplete="off">
</div>
<div>
<button type="submit">注册</button>
</div>
</form>
</body>
</html>
服务端代码,/routers/user.js
var express = require('express');
var {Users} = require("./webdb.js"); //引入数据库配置文件
//系统用户注册页面
router.get('/reg',function(req,res,next){
res.render('admin/reg')
})
//提交用户注册信息
router.post('/reg/info', function(req, res, next) {
let users = req.body
console.log(users)
Users.create(users).then(rel=>{
if(rel){
res.render('admin/result',{
msg: '注册成功',
urlName: '登录',
url: '/zchoutai'
})
}else{
res.render('admin/result',{
msg: '注册失败',
urlName: '注册',
url: '/users/reg'
})
}
}).catch(err=>{
res.render('admin/result',{
msg: '注册出现异常',
urlName: '注册',
url: '/users/reg'
})
})
});
反馈页面,/views/admin/result.ejs
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<div style="text-align:center;margin:30px;font-size:20px;">
<%=msg %>
<a href="<%=url %>">跳转到<%=urlName %></a>
</div>
</body>
</html>
2.3.2、用户登录
配置session,/app.js
var session = require('express-session');
app.use(cookieParser());//必须在此行下面添加session配置
app.use(session({
secret: 'recommand 128 bytes random string', // 建议使用 128 个字符的随机字符串
cookie: { maxAge: 20 * 60 * 1000 }, //cookie生存周期20*60秒
resave: true, //cookie之间的请求规则,假设每次登陆,就算会话存在也重新保存一次
saveUninitialized: true //强制保存未初始化的会话到存储器
}));
前台登录页面,/views/login.ejs
<!DOCTYPE html>
<html>
<body>
<form action="/users/login" method="post">
<input name="username" type="text" placeholder="用户名" autocomplete="off" />
<input name="pwd" type="password" placeholder="密码" autocomplete="off" />
<input value="登录" style="width:100%;" type="submit">
</form>
</body>
</html>
服务端处理用户登录,/routers/users.js
var express = require('express');
var router = express.Router();
var {Users} = require("./webdb.js")
//系统后台登录
router.post('/login', function(req, res, next) {
let users = req.body
Users.findOne(users).then(rel=>{
if(rel){
//保存session
req.session.username = users.username
req.session.pwd = users.pwd
res.redirect('/zchoutai/main')
}else{
res.render('admin/login',{
msg: '账号或密码错误'
})
}
}).catch(err=>{
res.render('admin/login',{
msg: '登录出现异常'
})
})
});
session的常用方法:
//保存session
req.session.username="张三"
//获取session
req.session.username
//重新设置cookie的过期时间
req.session.cookie.maxAge=1000;
//销毁session
req.session.destroy(function(err){
})
cookie的常用方法:
//设置cookie,HttpOnly 默认 false 不允许客户端脚本访问
//res.cookie(名称,值,{配置信息})
res.cookie("name",'zhangsan',{maxAge: 900000, httpOnly: true});
//获取cookie
req.cookies.name
//删除cookie
res.cookie('rememberme', '', { expires: new Date(0)});
res.cookie('username','zhangsan',{domain:'.ccc.com',maxAge:0,httpOnly:true});
cookie配置信息参数:
domain: 域名
name=value:键值对,可以设置要保存的 Key/Value,注意这里的 name 不能和其他属性项的名字一样
Expires: 过期时间(秒),在设置的某个时间点后该 Cookie 就会失效,如 expires=Wednesday, 09-Nov-99 23:12:40 GMT。
maxAge: 最大失效时间(毫秒),设置在多少后失效 。
secure: 当 secure 值为 true 时,cookie 在 HTTP 中是无效,在 HTTPS 中才有效 。
Path: 表示 在那个路由下可以访问到cookie。
httpOnly:是微软对 COOKIE 做的扩展。如果在 COOKIE 中设置了“httpOnly”属性,则通过程序(JS 脚本、applet 等)将无法读取到COOKIE 信息,防止 XSS 攻击的产生 。
singed:表示是否签名cookie, 设为true 会对这个 cookie 签名,这样就需要用 res.signedCookies 而不是 res.cookies 访问它。被篡改的签名 cookie 会被服务器拒绝,并且 cookie 值会重置为它的原始值。
加密 Cookie
1.配置中间件的时候需要传参
var cookieParser = require('cookie-parser');
app.use(cookieParser('123456')); 12
2.设置 cookie 的时候配置 signed 属性
res.cookie('userinfo','hahaha',{domain:'.ccc.com',maxAge:900000,httpOnly:true,signed:true}); 1
3.signedCookies 调用设置的 cookie
console.log(req.signedCookies); 1
demo:
/*
maxAge 过期时间
domain:'.aaa.com' 多个二级域名共享cookie
path 表示在哪个路由下面可以访问cookie
httpOnly:true 设置为true,表示只有在nodejs服务端可以操作cookie ,没法用js脚本语言操作cookie
signed属性设置成true 表示加密cookie信息
让用户看不到cookie明文信息
1.保存的时候加密
2.cookie-parser里面 signed属性设置成true
cookie的加密:
1.参数表示加密的随机字符串
app.use(cookieParser('sign'));
2.设置
res.cookie('userinfo','cookie222_info',{maxAge:600000,signed:true});
3.使用 获取
req.signedCookies
*/
var express = require('express');
var cookieParser = require('cookie-parser');
var app = express();
app.use(cookieParser('sign'));
app.get("/",function(req,res){
//console.log(req.cookies);
console.log(req.signedCookies); /*获取加密的cookie信息*/
res.send("你好nodejs");
});
app.get("/set",function(req,res){
//参数1:名字
//参数2:cookie的值
//参数3:cookie的配置信息
res.cookie('userinfo','cookie222_info',{maxAge:600000,signed:true});
res.send("设置cookie成功");
});
app.listen(3001,'127.0.0.1');