中国建设银行官网站汽车卡,wordpress 采集微信公众号,wordpress 外企模板,上海泵阀网站建设博客项目介绍
1. 目标
开发一个博客系统#xff0c;具备博客基本功能只开发 server 端#xff0c;不关心前端
2. 需求
首页、作者页、博客详情页登陆页管理中心、新建页、编辑页
3. 技术方案
数据如何存储
博客
idtitlecontentcreatetimeauthor1标题 1内容 11111112z…博客项目介绍
1. 目标
开发一个博客系统具备博客基本功能只开发 server 端不关心前端
2. 需求
首页、作者页、博客详情页登陆页管理中心、新建页、编辑页
3. 技术方案
数据如何存储
博客
idtitlecontentcreatetimeauthor1标题 1内容 11111112zhangsan2标题 2内容 21111111lisi
用户
idusernamepasswordrealname1zhangsan123张三2lisi.123李四
如何与前端对接接口即接口设计
描述接口方法url参数备注获取博客列表/api/blog/listgetauthor 作者keyword搜索关键字参数为空则不进行查询过滤获取一篇博客的详情/api/blog/detailgetid无新增一篇博客/api/blog/newpost无post中有新增的信息更新一遍博客/api/blog/updatepostidpostData中包含更新内容删除一篇博客/api/blog/delpostid无登陆/api/user/loginpost无postData包含用户名和密码
4. 开发接口原生node,不使用框架
4.1 http请求过程
DNS解析建立TCP连接三握四挥发起请求serve 端接收请求处理数据响应返回数据客户端接收到数据渲染页面执行脚本。
4.2 搭建开发环境
使用 nodemon 检测文件变化自动重启node项目使用 cross-env 设置环境变量。
4.3 路由和数据
初始化路由根据之前的技术方案的设计做出路由返回假数据将路由和数据分离符和设计原则。
4.4 项目结构
根目录下
bin/www.js 处理端口和 有关 http 服务的相关事宜app.js 处理基本逻辑导入路由函数传递req,res参数和 404 页面router 文件夹完成路由规则分为 blog.js、 user.js 只处理路由不关心数据的处理controller/blog.js 文件 连接数据库处理数据在 router/blog.js 中使用类似工具model/resModel 文件 完成响应数据模块 resModel封装成功和失败类在 router/blog.js 的某个路径成功获取数据后就使用成功类响应数据和消息提示。
4.5 处理 post
使用 promise 优化 post 请求的数据放入 req.body 里。对于请求方法不正确或者请求头不匹配直接 resolve 一个空对象并不需要当作一个错误。应为读取 data 的过程是异步的所以需要将原来的命中路由的逻辑放在promise中,在 app.js 中实现。
部分代码如下
/*** 处理 post data*/
const getPostData (req) {const promise new Promise((resolve, reject) {// 方法不是 post...// 请求头格式不是 json...let postData ;req.on(data, (chunk) {// 将json格式的参数转为字符串保存postData chunk.toString();});req.on(end, () {// nullif (!postData) {resolve({});return;}// successresolve(JSON.parse(postData));});});return promise;
};// 处理 post datagetPostData(req).then((postData) {// 将数据放入bodyreq.body postData;/*** blog 路由*/const blogData handleBlogRouter(req, res);// 命中 blog 路由.../*** user 路由*/const userData handleUserRouter(req, res);// 命中 user 路由... // 处理 404...});5.数据存储
5.1.实现思路
建立数据库myblog建立博客表、和用户表conf/db.js 下封装数据库工具,处理开发和生产环境下的数据库连接配置db/mysql.js使用promise获取数据库的数据,resolve给getList工具,在getList中只需处理 sql语句,然后在app.js 中使用.then,发送 res.end 给客户端
6.登陆功能
核心登陆鉴权和信息存储 cookie和session session 写入 redis 开发登陆功能-和前端联调 Nginx 反向代理
session/cookie
前端保存 cookie 携带 userId,后端通过是否有 userId 进行一系列操作当登陆成功但是没有 session 时需要设置 session
目前有关session的问题
session 是直接储存 js 变量放在 node.js 进程内存中第一进程内存有限访问量过大时内存爆增可能导致服务崩溃第二正式线上运行时多进程进程之间无法共享内存。
解决使用 redis
为什么
session 访问非常频繁不能使用 mysql,对性能要求高。并且 session 可以丢失无须内存永久保存。session数据量不大没必要使用 mysql
要使用 Redis在 Node.js 中存储会话session你需要执行以下步骤
1. 下载和安装 Redis
官方网站https://redis.io/download
启动服务执行 redis-server,建立连接和操作执行redis-cli
基本使用语法
添加set [key] [value]获取get [key]删除del [key]获取所有key: keys *
2. 配置 Redis
安装完成后你需要配置 Redis 服务器。打开 Redis 配置文件redis.conf并进行必要的更改。确保 bind 配置项设置为允许远程连接如果需要从 Node.js 应用程序访问 Redis。
3. 在 Node.js 中安装 Redis 客户端
npm install redis这将安装 Redis 客户端库使你能够在 Node.js 应用程序中与 Redis 进行交互。
4. 在 Node.js 应用程序中存储会话
首先你需要在 Node.js 应用程序中创建与 Redis 的连接。使用 Redis 客户端库提供的方法进行连接。
const redis require(redis);
const client redis.createClient(); // 创建与 Redis 的连接client.on(error, (err) {console.error(Redis连接错误:, err);
});// 储存会话示例
app.post(/login, (req, res) {// 处理用户登录逻辑// ...// 在 Redis 中存储会话client.set(req.sessionID, JSON.stringify(req.user), (err, reply) {if (err) {console.error(存储会话错误:, err);return res.status(500).send(存储会话失败);}console.log(会话已存储:, reply);res.send(登录成功);});
});在上面的示例中我们使用 Redis 客户端的 set 方法将会话数据以 JSON 字符串的形式存储在 Redis 中。req.sessionID 是会话的唯一标识符通常存储在用户的浏览器 cookie 中。req.user 是用户对象我们将其转换为 JSON 字符串后存储在 Redis 中。
和前端联调
登陆依赖 cookie 必须使用 浏览器联调cookie 跨域不共享前端和 server 端必须同域需要使用 nginx 代理使前后端同域
登陆总结
Cookie和Session都是用于跟踪用户状态的技术。它们之间有一些区别 CookieCookie是一种存储在客户端的小型文本文件用于保存用户的一些信息。当用户访问一个网站时服务器会将Cookie发送到用户的浏 用户在登录页面输入用户名和密码。 客户端将用户名和密码发送到服务器。 服务器验证用户名和密码。如果验证成功服务器会创建一个Session并将Session ID发送给客户端通常通过Cookie。 客户端保存Session ID并在后续请求中将其发送回服务器。 服务器根据Session ID识别用户并获取其会话信息。
在使用Redis存储Session信息时可以将Session ID作为键将用户会话信息作为值。这样当服务器需要获取用户会话信息时可以直接从Redis中查询而不需要访问数据库从而提高性能。同时由于Redis支持分布式存储可以方便地扩展Session存储容量。
7.日志
访问日志 access log (最重要)自定义日志包括自定义事件、错误记录。
大致思路
封装 utils log.js 工具使用 writerStream 分别实现 access 访问日志和错误、事件日志分别导出使用
/*** 写日志的一小步操作* param {Function} writeStream* param {string} log*/
const writeLog function (writeStream, log) {writeStream.write(log \n);
};/*** 写入流函数* param {string} fileName -logs 文件夹下的文件名你将要写入的文件* return writeStream*/
const createWriteStream function (fileName) {const fullFilePath path.join(__dirname, ../, ../, logs, fileName);const writeStream fs.createWriteStream(fullFilePath, { flags: a });return writeStream;
};// 1. 写入访问日志
// 利用 createWriteStream 函数创建 access 写入流
const accessWriteStream createWriteStream(access.log);
const access function (log) {writeLog(accessWriteStream, log);
};// 2. 写入错误日志
...
// 3. 写入事件日志
...
module.exports {...
};
日志拆分
使用 linux 的 crontab 命令即定时任务。
使用 crontab -e 写入在什么时候执行什么文件
* 0 * * * sh /Users/jiangchuanyou/Desktop/项目/node博客项目/src/utils/copy.sh以上就是在每天凌晨0点执行以下脚本
#!/bin/sh
cd /Users/jiangchuanyou/Desktop/项目/node博客项目/logs
cp access.log $(date %Y-%m-%d).access.log
echo access.log8. 安全
sql 注入窃取数据库内容
解决方案mysql 自带 escape 函数
xss 攻击窃取前端 cookie 内容
解决方案转换特殊字符,使用 xss 函数下载 npm 包 xss -s,直接使用 xss 函数包裹变量以免生成危险的 js 代码
前端预防 xss 攻击 输入验证和过滤对于用户输入的数据进行输入验证和过滤确保只接受预期的数据类型和格式。可以使用正则表达式、白名单过滤或使用专门的输入验证库来检查和清理用户输入。 HTML转义将用户输入的数据进行适当的 HTML 转义确保任何特殊字符都被转义为它们的等效实体表示形式。这样可以防止恶意脚本在页面中执行。可以使用专门的转义函数或库如htmlspecialchars等。 跨站点脚本保护禁止内联 JavaScript 代码、限制只接受特定的 HTML 标签和属性。使用安全的 HTML 渲染库或模板引擎这些库会自动转义用户输入。 HTTP-only Cookie将敏感信息存储在 HTTP-only Cookie 中确保 JavaScript 无法访问该信息。这样可以减少 XSS 攻击者窃取会话信息的可能性。 内容安全策略Content Security PolicyCSP使用 CSP 可以限制页面中可以执行的脚本和资源。通过配置 CSP可以指定允许的域、资源类型和加载方式以减少 XSS 攻击的风险。 防止拼接 HTML 字符串避免直接拼接用户输入的数据来构建 HTML 字符串。而是使用 DOM 操作或模板引擎来动态生成 HTML确保数据被正确地转义和处理。 安全编码实践遵循安全的编码实践避免在代码中出现漏洞如不信任的数据源、不安全的 eval() 使用、动态执行用户输入的代码等。
密码加密保障用户信息安全
9. 总结