综合应用服务端知识点搭建项目

下载安装所需的第三方模块

npm init -y
npm i express cors mysql
# express 用于搭建服务器
# cors 用于解决跨域
# mysql 用于操作数据库# 后面用到什么,再下载

创建app.js

之前,我们开启一个服务器,js文件名,一般都是 01-xxx.js 03-xxx.js

对于正常的一个项目来说,用于开启服务的js文件,一般都叫做 app.js

// 开启服务
const express = require('express');
const app = express();
app.listen(3006, () => console.log('server running~'));

使用路由模块精简项目结构

使用路由模块的原因(意义)

  • 试想,如果项目有100个路由(接口),全部放到app.js中,这样的代码不好维护,效率也比较低下
  • 所以需要按照路由(接口)功能的不同,分别使用小文件存放这些路由(接口),这些小文件就叫做路由模块
    • 比如,登录注册相关的,全部放到 ./routers/login.js
    • 比如,文章处理相关的,全部放到 ./routers/article.js
    • 比如,书籍管理相关的,全部放到 ./routers/books.js

代码如何实现

  • 路由文件中的代码

    • 加载express
    • 创建路由对象
    • 将路由(接口)挂载到路由对象上
    • 导出路由对象
/*** 1. 加载express* 2. 创建路由对象* 3. 把路由挂载到路由对象上* 4. 导出路由对象*/const express = require('express');
const router = express.Router();// 下面是图书管理相关的路由
router.get('/getbooks', (req, res) => {res.send('我是获取书籍的接口');
});router.post('/addbook', (req, res) => {});router.get('/delbook', (req, res) => {});module.exports = router;
  • app.js 中的代码

    • 加载路由模块,并注册成中间件。注册的时候,可以统一加前缀
// 开启服务
const express = require('express');
const app = express();
app.listen(3006, () => console.log('server running~'));// 加载路由模块,并注册成中间件
let books = require('./routers/books');
app.use('/api', books);

开启服务(nodemon app.js) ,然后通过浏览器来测试一下你的接口是否能够正常访问

创建数据库、数据表

数据库,还可以使用昨天的 user 数据库。

在里面创建一张数据表(books)

添加几条模拟数据:

粗略的完成获取书籍的接口

  • 目前:

    • 数据准备好了
    • 接口能够正常访问了
  • 下面要做的事情:

    • getbooks接口中,通过mysql模块,查询所有的书籍,并把结果响应给客户端
    • 中间件解决跨域问题

getbooks接口

router.get('/getbooks', async (req, res) => {// 查询数据库user、数据表books里面的数据,把查询的结果响应给客户端const mysql = require('mysql'); // require加载一个模块后,会缓存起来const conn = mysql.createConnection({host: 'localhost',user: 'root',password: '12345678',database: 'user' // 填写数据库名});conn.connect();conn.query('select * from books', (err, result) => {if (err) return console.log(err);res.json({status: 200,msg: '获取成功',data: result});});conn.end();
});

应用级别的中间件解决跨域

  • 应用级别的中间件

    • 写到app.js中的中间件
    • 该中间件会影响所有的路由
  • 路由级别的中间件
    • 写到 路由文件中的中间件
    • 该中间件只会影响当前的路由文件

因为整个项目的全部路由都需要解决跨域问题,所以需要定义应用级别的中间件

所以,在app.js中,加入如下代码:

// 配置中间件,解决跨域问题
app.use((req, res, next) => {res.set({'Access-Control-Allow-Origin': '*'});next();
});

封装db.js

试想,后面还有很多路由中需要对数据库进行操作,难道每次执行SQL语句,都要写5个步骤(操作MySQL的5个步骤)吗?

:肯定不是,那样的话,代码太多。代码复用性太差了

解决办法:封装

具体做法

  • 创建 db.js
  • 里面封装 使用mysql模块的5个步骤
  • 导出函数
  • 其他路由中,需要加载(导入)db模块,然后调用函数即可

db.js 中的代码:

function db(sql, params, callback) {const mysql = require('mysql');const conn = mysql.createConnection({host: 'localhost',user: 'root',password: '12345678',database: 'user' // 填写数据库名});conn.connect();conn.query(sql, params, callback);conn.end();
}// 导出函数
module.exports = db;

getbooks接口中使用:

// 获取书籍接口
router.get('/getbooks', async (req, res) => {// 查询数据库user、数据表books里面的数据,把查询的结果响应给客户端db('select * from books', null, (err, result) => {if (err) return console.log(err);res.json({status: 200,msg: '获取成功',data: result});});
});

使用Promise

如果查询书籍信息的时候,还要查询总记录数,怎么办?

:嵌套查询,嵌套的层数太多,就会形成回调地狱

解决办法:使用Promise

具体做法

  • 在db.js中,加个一个封装Promise的函数db2
  • db2中调用db函数,从而完成Promise的封装
  • 导出db2
function db(sql, params, callback) {const mysql = require('mysql');const conn = mysql.createConnection({host: 'localhost',user: 'root',password: '12345678',database: 'user' // 填写数据库名});conn.connect();conn.query(sql, params, callback);conn.end();
}function db2 (sql, params) {return new Promise((resolve, reject) => {// 这里写异步代码db(sql, params, (err, result) => {err ? reject(err) : resolve(result);});});
}// 导出函数
module.exports = db2;

优化上述两个函数

function db (sql, params = null) {const mysql = require('mysql'); // require加载一个模块后,会缓存起来const conn = mysql.createConnection({host: 'localhost',user: 'root',password: '12345678',database: 'user' // 填写数据库名});return new Promise((resolve, reject) => {// 这里写异步代码conn.connect();conn.query(sql, params, (err, result) => {err ? reject(err) : resolve(result);});conn.end();});
}// 导出函数
module.exports = db;

完整的图示

Web 开发模式

目前主流的 Web 开发模式有两种,分别是:

  1. 基于服务端渲染的传统 Web 开发模式
  2. 基于前后端分离的新型 Web 开发模式

服务端渲染的开发模式

特点:

  • 所有的web资源由同一个服务器统一管理(前后端代码必须放到一起)

  • 页面和页面中使用的数据,由服务器组装,最后将完整的HTML页面响应给客户端

代码:

// 用于开启服务const fs = require('fs');
const express = require('express');
const app = express();
app.listen(3000, () => console.log('启动了'));// 显示首页的接口
app.get('/index.html', (req, res) => {// res.send('1111')fs.readFile('./public/index.html', 'utf-8', (err, data) => {if (err) return console.log(err);data = data.replace('{{title}}', '悯农');data = data.replace('{{content}}', '锄禾日当午,汗滴禾下土');res.send(data);});
});

真实的服务端渲染模式和前后端分离的模式,难度上差不多。

优点:

  • **前端耗时少。**因为服务器端负责动态生成 HTML 内容,浏览器只需要直接渲染页面即可。尤其是移动端,更省电。
  • 有利于SEO。因为服务器端响应的是完整的 HTML 页面内容,所以爬虫更容易爬取获得信息,更有利于 SEO(搜索引擎)。

缺点:

  • **占用服务器端资源。**即服务器端完成 HTML 页面内容的拼接,如果请求较多,会对服务器造成一定的访问压力。

  • 不利于前后端分离,开发效率低。使用服务器端渲染,则无法进行分工合作,尤其对于前端复杂度高的项目,不利于 项目高效开发。

前后端分离的开发模式

特点:

  • 依赖于Ajax技术
  • 后端不提供完整的 HTML 页面内容,而 是提供一些 API 接口
  • 前端通过 Ajax 调用后端提供的 API 接口,拿到 json 数据 之后再在前端进行 HTML 页面的拼接,最终展示在浏览器上。

简而言之,前后端分离的 Web 开发模式,就是后端只负责提供 API 接口,前端使用 Ajax 调用接口的开发模式。

优点:

  • **开发体验好。**前端专注于 UI 页面的开发,后端专注于api 的开发,且前端有更多的选择性。
  • **用户体验好。**Ajax 技术的广泛应用,极大的提高了用户的体验,可以轻松实现页面的局部刷新。
  • **减轻了服务器端的渲染压力。**因为页面最终是在每个用户的浏览器中生成的。

缺点:

  • **不利于SEO。**因为完整的 HTML 页面需要在客户端动态拼接完成,所以爬虫对无法爬取页面的有效信息。(解决方 案:利用 Vue、React 等前端框架的 SSR (server side render)技术能够很好的解决 SEO 问题!)

如何选择 Web 开发模式

不谈业务场景而盲目选择使用何种开发模式都是耍流氓。

  • 比如企业级网站(公司的网站),主要功能是展示而没有复杂的交互,并且需要良好的 SEO,则这时我们就需要使用服务器端渲染;

  • 而类似后台管理页面,交互性比较强,不需要 SEO 的考虑,那么就可以使用前后端分离的开发模式。

  • 另外,具体使用何种开发模式并不是绝对的,为了同时兼顾首页的渲染速度前后端分离的开发效率,一些网站采用了 首屏服务器端渲染,即对于用户最开始打开的那个页面采用的是服务器端渲染,而其他的页面采用前后端分离开发模式。

身份认证机制

对于服务端渲染和前后端分离这两种开发模式来说,分别有着不同的身份认证方案:

  • 服务端渲染推荐使用 Session 认证机制(Session也会用到Cookie)
  • 前后端分离推荐使用 JWT 认证机制

Cookie

原理

实现身份认证

  • 搭建基础的服务器

    • 下载安装第三方模块 expresscookie-parser

    • 创建app.js

    • 加载所需模块

      • const express = require('express');
      • const cookieParser = require('cookie-parser');
  • 中间件配置 cookie-parser
    • app.use(cookieParser())
  • 实现三个路由
    • /login.html (里面直接响应login.html页面)
    • /api/login
    • /index.html (里面直接响应index.html页面)
  • 创建存放index页面的public文件夹
    • 创建index.html
    • 创建login.html
  • 完成登录接口
    • 如果登录成功,设置cookie。res.cookie('key', 'value', 配置项);
    • 跳转到 /index.html 路由
  • /index.html 路由中,根据cookie判断是否登录,从而完成身份认证

详见代码

const express = require('express');
const cookieParser = require('cookie-parser');
const path = require('path');const app = express();
app.listen(3000, () => console.log('启动了'));// 接收POST请求体
app.use(express.urlencoded({extended: false}));
// 配置cookie-parser
app.use(cookieParser());// 准备三个路由// 用于显示登录页面
app.get('/login.html', (req, res) => {// sendFile方法,可以读取文件,并将读取的结果响应给客户端// 要求,参数必须是一个绝对路径res.sendFile(path.join(__dirname, 'public', 'login.html'));
});// 用于完成登录验证的(判断账号密码是否正确的接口)
app.post('/api/login', (req, res) => {// console.log(req.body);// 约定,假设账号是 admin、密码是123if (req.body.username === 'admin' && req.body.password === '123') {// 登录成功,跳转到index.html// 设置cookie// res.cookie('key', 'value', '选项');// res.cookie('isLogin', 1); // 没有填选项,默认cookie有效期是会话结束res.cookie('isLogin', 1, {maxAge: 2*60*1000});res.send('<script>alert("登录成功"); location.href="/index.html";</script>');} else {// 登录失败}
});// 显示index.html页面的
app.get('/index.html', (req, res) => {// 获取cookie// console.log(req.cookies);if (req.cookies.isLogin && req.cookies.isLogin === '1') {res.sendFile(path.join(__dirname, 'public', 'index.html'));} else {// 没有登录res.send('<script>alert("请先登录"); location.href="/login.html";</script>');}
});

优缺点

  • 优点

    • 体积小
    • 客户端存放,不占用服务器空间
    • 浏览器会自动携带,不需要写额外的代码,比较方便
  • 缺点
    • 客户端保存,安全性较低。但可以存放加密的字符串来解决
    • 可以实现跨域,但是难度大,难理解,代码难度高
    • 不适合前后端分离式的开发

适用场景

  • 传统的服务器渲染模式
  • 存储安全性较低的数据,比如视频播放位置等

Session

原理

实现身份认证

  • 搭建基础的服务器

    • 下载安装第三方模块 expressexpress-session

    • 创建app.js

    • 加载所需模块

      • const express = require('express');
      • const session = require('express-session');
  • 中间件配置 session

    app.use(session({secret: 'adfasdf', // 这个随便写saveUninitialized: false,resave: false
    }))
    
  • 实现三个路由

    • /login.html (里面直接响应login.html页面)
    • /api/login
    • /index.html (里面直接响应index.html页面)
  • 创建存放index页面的public文件夹

    • 创建index.html
    • 创建login.html
  • 完成登录接口

    • 如果登录成功,使用session记录用户信息。

      req.session.isLogin = 1;
      req.session.username = req.body.username;
      
    • 跳转到 /index.html 路由

  • /index.html 路由中,根据session判断是否登录,从而完成身份认证

详见代码

const express = require('express');
const session = require('express-session');
const path = require('path');const app = express();
app.listen(3000, () => console.log('启动了'));// 接收POST请求体
app.use(express.urlencoded({extended: false}));
// 配置session
app.use(session({secret: 'asdf23sfsd23',// 下面两项,设置成true或者false,都可以。使用内存存储session的时候,下面两项没作用saveUninitialized: false,resave: false
}));// 准备三个路由// 用于显示登录页面
app.get('/login.html', (req, res) => {// sendFile方法,可以读取文件,并将读取的结果响应给客户端// 要求,参数必须是一个绝对路径res.sendFile(path.join(__dirname, 'public', 'login.html'));
});// 用于完成登录验证的(判断账号密码是否正确的接口)
app.post('/api/login', (req, res) => {// console.log(req.body);// 假设账号任意,密码必须是123if (req.body.password === '123') {// 假设登录成功// req.session.xxxx = 'yyyy'req.session.isLogin = 1;
/*<p>欢迎你:{{username}}</p>
*/req.session.username = req.body.username;// 做出响应res.send('<script>alert("登录成功"); location.href="/index.html";</script>');}
});// 显示index.html页面的
app.get('/index.html', (req, res) => {// 获取session    req.sessionif (req.session.isLogin && req.session.isLogin == 1) {const fs = require('fs');fs.readFile('./public/index.html', 'utf-8', (err, data) => {if (err) return console.log(err);// 更换用户名data = data.replace('{{username}}', req.session.username);res.send(data);});} else {res.send('<script>alert("请登录"); location.href="/login.html";</script>');}});

优缺点

  • 优点

    • 服务端存放,安全性较高
    • 浏览器会自动携带cookie,不需要写额外的代码,比较方便
    • 适合服务器端渲染模式
  • 缺点
    • 会占用服务器端空间
    • session实现离不开cookie,如果浏览器禁用cookie,session不好实现
    • 不适合前后端分离式的开发

适用场景

  • 传统的服务器渲染模式
  • 安全性要求较高的数据可以使用session存放,比如用户私密信息、验证码等

Node — 第六天(前后端分离)及(身份验证)相关推荐

  1. 前后端分离之权限验证

    前后端分离之权限验证 原理:将登录验证的请求头中后端生成的秘钥(token)接收后存储在cookie内,在再次请求数据时添加在请求头中发送给后端验证,请求数据. 代码: 登录ajax: $scope. ...

  2. SSM+JWT实现前后端分离的token验证

    SSM+JWT实现前后端分离的token验证 前言 什么是JWT 基于Token的验证流程 JWT的Token实现 后端部分 前端部分 测试 项目完整地址 前言 以前写的web项目都是没有前后端分离的 ...

  3. 前后端分离的用户验证原理及Spring Boot + JWT的框架搭建(附完整的框架代码)之二

    本篇承接上一篇,关于Session以及JWT Token参考: 前后端分离的用户验证原理及Spring Boot + JWT的框架搭建(附完整的框架代码)之一 框架整体描述 框架使用Spring Bo ...

  4. node+vue前后端分离实现登录时使用图片验证码

    记录一下前端使用验证码登录的过程 后端用的是node.js,关键模块是svg-captcha 前端使用的是vue2 最后的登录界面如下: 后端代码 先上代码,然后解释 const svgCaptcha ...

  5. Vue2+Node.js前后端分离项目部署到云服务器

    本文参考教程: NodeJS项目部署到阿里云ECS服务器全程详解 - 知乎本文详细介绍如何部署NodeJS项目到阿里云ECS上,以及本人在部署过程中所遇到的问题.坑点和解决办法,可以说是全网最全最详细 ...

  6. spring security 前后端分离 进行用户验证 权限登陆的实现代码(看不懂??直接cv)

    目录 目录 前言: 一.所需依赖 二.application.properties 三.工具类 3.1ApplicationContextUtils 3.2JwtUtils 3.3ResponseRe ...

  7. 前后端分离的用户验证原理及Spring Boot + JWT的框架搭建(附完整的框架代码)之一

    Java Web项目开发方式 Java Web的开发有以下几种: 单纯JSP开发 结合模板引擎的JSP开发(比如Thymeleaf),模板引擎提供了更多页面和数据结合的组件,很大程度减轻了页面开发的工 ...

  8. 基于SpringBoot,vue,node的前后端分离小米商城的设计与实现

    1,项目介绍 注:本项目拥有两个版本,下单前请及时告知自己所需的版本(两个版本只有技术栈不同): 版本一:spring boot+vue+MySQL 版本二:node.js+vue+MySQL 项目简 ...

  9. java不同项目加token访问_利用JWT实现前后端分离的Token验证

    写在前面:本篇文章的代码图片展示均使用carbon绘制,图片质量很高,如果图片过小可以点击查看原图.项目实例前端部分使用基于Angular的Ionic框架(TypeScript),使用Spring B ...

  10. 前后端分离vue2+node易购商城后台管理系统

    继续学习vue 之前写了个全栈后台管理系统,功能上大体已经满足了后台管理的全部内容.利用空余时间又重新写了一个,虽然页面上精简了很多,但是基本上都是自己写的,而且加入了自己的理解,尤其是vuex那一块 ...

最新文章

  1. jQuery判断当前元素显示状态并控制元素的显示与隐藏
  2. discuz邮件设置PHP,Discuz!6.0—如何配置发送邮件的参数
  3. EFCore之增删改查
  4. linux网络编程之inet_pton和inet_ntop函数
  5. C语言 指针数组和数组指针区别 - C语言零基础入门教程
  6. 线程池参数如何设置?
  7. 前端悬浮窗效果_web前端入门到实战:css过渡和动画解析文
  8. java中单,单|的意思,按位操作符详述
  9. B. Hierarchy
  10. mysql 5.7 连接数_mysql5.7出现大量too many connections及too many open files错误,且配置最大连接数未生效...
  11. OpenRefine开源数据清洗软件的GREL语言
  12. 【ArcGIS Pro微课1000例】0009:ArcGIS Pro地理配准完整教程(建议收藏)
  13. 引用防删——JAVA设计模式总结之六大设计原则
  14. top邮箱怎么登录,解决方案
  15. ImageLoader 修改个人头像
  16. 嵌入式安全被忽视的 3 个原因
  17. C语言学习纯纯小白-1,C语言代码开头为什么要有#include <stdio.h>
  18. 金字塔打印(C语言)
  19. 解决使用webstorm新建vue项目时‘gyp: No Xcode or CLT version detected!’报错
  20. 安卓手机安装google套件的详细步骤

热门文章

  1. float,double等精度丢失问题
  2. 高斯混合模型GMM的理解
  3. 【边缘检测】BDCN:Bi-Directional Cascade Network for Perceptual Edge Detection
  4. 模型越复杂越容易惰性_ML模型的惰性预测
  5. 特征选择 回归_如何执行回归问题的特征选择
  6. 辍学的名人_辍学效果如此出色的5个观点
  7. 内核中引发bug并打印信息
  8. 有人说,如果有条件一定要远离穷人,你赞成吗?
  9. java整合html_springBoot整合mybatis、jsp 或 HTML
  10. java中怎么使用json数据_JAVA中使用JSON进行数据传递