原生node开发简单的博客系统

以下所涉及技术模块不会在此文章中教学,文章只做一个思路的记录,如有错误欢迎指正。还有就是文章只注重利用nodejs设计后端的服务,前端页面只会简单渲染。

  • mysql
  • redis
  • nginx

技术方案

  • 数据如何存储
  • 如何与前端对接,即接口设计

数据存储

  • 存储博客数据

img

  • 存储用户数据

img

接口设计

img

项目结构

image-20210420105842041

  1. bin/www,js: 创建createServer的基础服务
  2. app.js: 与http的基础配置相关,不处理业务关系
  3. router.js: 只处理路由相关
  4. controller: 只关心数据,真正获取数据
  5. model: 对成功与失败请求返回的数据进行统一处理

建表

img

img

nodejs处理http请求

利用nodejs内置模块http,创建http服务。

这里简单介绍一下http请求的流程:

  1. 输入地址
  2. dns解析,建立tcp连接,发送http请求(经典三次握手)
  3. sever端接到http请求,处理并返回
  4. client端收到返回数据,并渲染页面

顺便简单介绍一下三次握手:

  • 客户端询问服务器你是否可用
  • 服务器告诉客户端自己可用
  • 客户端再次告诉服务端我知道了,开始访问

核心模块

登录

重点: 登录校验和登录信息存储。

这边涉及两个概念:cookie和session。

cookie是登陆必要的基础,session是登陆的解决方案。

写入session的数据最终会写入redis中,避免存储在内存中占用内存。

简单介绍一下cookie:

  • cookie是存储在浏览器中的一段字符串(最大5kb)

  • cookie跨域不共享

  • 存储结构化数据,格式如k1=v1;k2=v2

  • 每次发送http请求,会将请求域的cookie一起发送给server端,如下图

  • server端可以修改cookie并返回给浏览器

  • 浏览器中可以通过js修改cookie(有限制)

img

client端

查看cookie的三种方式:

  • 从response cookie查看
  • 从application cookie查看
  • 控制台document.cookie查看

js修改cookie可以通过: document.cookie = xxx;(追加cookie非重置)

server端

查看cookie:res.headers.cookie

修改cookie: res.setHeader(‘Set-cookie’,username=${data.username};path=/;httpOnly

再说说session

session可以避免用户信息暴露。

通过在cookie中存入一个key,而在session中存入一样的key和value,这样可以避免cookie大小的问题,同时避免cookie泄露用户关键信息,即使泄露了当前存入的key,也没有什么用。

故在cookie中存储userid,在session中存入key为userid,value即为用户信息对象。

img

session的问题

目前session直接是js变量,放在nodejs 的进程中,进程内存有限,访问量过大,会造成内存暴增。正式线上运行时多进程的,进程之间内存无法共享。

img

Stack存储的是基础变量, session存在Heap中

操作系统会限制内存的一个最大可用内存,nodesjs在32位系统中1.6G, 在64位系统中也不会超过3G

img

nodejs是分成多个进程跑的

img

解决方案: 使用redis

redis的特点

  • webserver最常用的缓存数据库,数据存放在内存中

  • 相比mysql没访问速度快(内存和硬盘不是一个数量级的)

  • 但是成本更高,可存储的数据量更小(内存的硬伤)

img

redis作用

  • 将web server和redis拆分成为两个单独个服务

  • 双方都是独立的,都是可扩展的(例如都扩展成集群)

  • 包括mysq也是一个单独的服务可扩展

为什么session适合用redis

  • session访问频繁,对性能要求极高

  • session可不考虑断电丢失数据的问题(内存的硬伤)

  • session的数据量不会太大(相比mysq中的存储数据)

为何网站数据不适合用redis

  • 操作频率不是太高(相比session)

  • 断电不能丢失,必须保留

  • 数据量太大,内存成本太高

反向代理模块

解决方案:nginx反向代理。(这边没有直接使用服务端渲染,还是前后端分离)

img

解释一下反向代理和正向代理

反向代理: 对客户端不可见的代理。客户端控制不了,server端全部涵盖了,对客户端来说就是一个黑盒。

正向代理: 客户端可以控制的代理。比如说某公司的内网在家里访问不到,但是客户端安一个插件就可以访问得到,这样客户端就可以控制,叫做正向代理。

日志模块

日志是服务端一个重要的模块,方便查看操作信息和错误记录。

这里需要以下两种日志:

  • 访问日志access log(server端最重要的日志)
  • 自定义日志(包括自定义事件、错误记录)

这边利用fs模块和stream模块实现功能:

  • 对日志文件拆分

    • 日志内容会慢慢积累,放在一个文件中不好处理

    • 按时间划分日志文件,如2020-4-16.access.log

    • 实现方式:linux的crontab命令,即定时任务

  • 对日志内容分析

    • 针对acess.log日志,分析chrome占比

    • 日志是按行存储的,一行就是一条日志

    • 使用nodejs的readline(基于stream,效率高)

  • 存储到文件中。

安全模块

常见安全问题:

  • sql注入:窃取数据库内容

    攻击方式: 输入一个sql片段,最终拼接成一段攻击代码

    预防措施:使用mysql的escape函数处理输入内容即可

  • xss攻击:窃取前端的cookie内容

    攻击方式:在页面展示内容中掺杂js代码,以获取网页信息

    预防措施:转换生成js的特殊字符

整体思路

img

代码实现

https://gitee.com/lin-mingjiang/node-blog.git