【Node.js实战】一文带你开发博客项目(使用假数据处理)

news2025/2/26 6:54:17

个人简介

👀个人主页: 前端杂货铺
🙋‍♂️学习方向: 主攻前端方向,也会涉及到服务端
📃个人状态: 在校大学生一枚,已拿 offer(秋招)
🥇推荐学习:🍍前端面试宝典 🍉Vue2 🍋Vue3 🍓Vue2&Vue3项目实战 🥝Node.js
🌕个人推广:每篇文章最下方都有加入方式,旨在交流学习&资源分享,快加入进来吧

Node.js系列文章目录

内容参考链接
Node.js(一)初识 Node.js
Node.js(二)Node.js——开发博客项目之接口

文章目录

  • Node.js系列文章目录
    • 一、前言
    • 二、博客项目实现
      • 1、文件目录
      • 2、环境配置
      • 3、开发接口
      • 4、开发过程
    • 三、各个接口的测试
    • 四、写在最后(附源码)


一、前言

2022-10-24,首先祝大家节日快乐,工作和学习中再无 bug~~

本文 开发博客项目的接口,是使用的 假数据 处理的。

后续 的文章还会使用 各种框架和数据库进行重构,敬请期待~

该项目的 开发模式,是 常规通用 的方式,所以学习这种 层次渐进的开发模式 也是很有意义的!

二、博客项目实现

1、文件目录

项目开发的层次感:

www.js(第一层)——> app.js(第二层)——> ./router(第三层)——> ./controller(第四层)

第一层:项目执行的地方
第二层:一些配置,请求响应头,格式化,promise实例等
第三层:路由接口,只关心路由,不管深层次的逻辑
第四层:只关心数据的地方

在这里插入图片描述

2、环境配置

初始化 package.json(配置相关文件)

npm init -y

安装依赖(安装相关依赖文件)

npm install

安装 nodemon(自动重启服务)

npm install nodemon cross-env --save-dev 

在这里插入图片描述

3、开发接口

博客相关接口 && 用户相关接口

在这里插入图片描述

4、开发过程

./bin/www.js 文件

  • 项目执行的文件
  • 引入 http 模块
  • 创建服务,传入文件(易开发和维护)
  • 监听端口
// 引入 http 内置模块
const http = require('http')

// 端口
const PORT = 8000 
// 引入 app.js
const serverHandle = require('../app')
// 创建服务
const server = http.createServer(serverHandle)
// 监听端口
server.listen(PORT)

…/src/app.js 文件

  • 参数处理
  • 响应头
  • 格式化
  • 处理博客和用户的相关路由
// 便于处理 url 
const querystring = require('node:querystring')
// 博客相关路由
const handleBlogRouter = require('./src/router/blog')
// 用户登录相关路由
const handleUserRouter = require('./src/router/user')

// 用于处理 POST 请求的数据
const getPostData = (req) => {
    // 创建 promise 实例
    const promise = new Promise((resolve, reject) => {
        // 不是 post 请求 直接返回
        if (req.method !== 'POST') {
            resolve({})
            return
        }
        // 请求头不是 application/json 格式 直接返回
        if (req.headers['content-type'] !== 'application/json') {
            resolve({})
            return
        }
        // 初始化 postData
        let postData = ''
        // 每次发送的数据 记录在 postData 中
        req.on('data', chunk => {
            postData += chunk.toString()
        })
        // 数据发送完成 转义 JSON 为对象
        req.on('end', () => {
            if (!postData) {
                resolve({})
                return
            }
            resolve(
                JSON.parse(postData)
            )
        })
    })
    // 返回实例对象
    return promise
}

// 处理服务
const serverHandle = (req, res) => {
    // 设置响应头的格式 JSON
    res.setHeader('Content-type', 'application/json')

    // 获取请求地址 path
    const url = req.url
    // 截取前半部分的地址 ? 前面的部分
    req.path = url.split('?')[0] // 获取 ? 的前半部分

    // 截取后半部分的地址 ? 后面的部分 也是要查询的地址
    req.query = querystring.parse(url.split('?')[1])

    // 处理 post data
    getPostData(req).then(postData => {
        // 解析 POST 请求中的数据
        req.body = postData

        // 处理 blog 路由
        const blogData = handleBlogRouter(req, res)
        // 请求成功 格式化 blogData 并结束
        if (blogData) {
            res.end(
                JSON.stringify(blogData)
            )
            return
        }

        // 处理 user 路由
        const userData = handleUserRouter(req, res)
        // 请求成功 格式化 userData 并结束
        if (userData) {
            res.end(
                JSON.stringify(userData)
            )
            return
        }

        // 未命中路由,返回 404
        res.writeHead(404, {
            "Content-type": "text/plain"
        })
        // 在浏览器显示的内容
        res.write("404 Not Found\n")
        // 结束服务端和客户端的连接
        res.end()
    })

}
// 模块化 把 serverHandle 暴露出去
module.exports = serverHandle

…/src/model/resModel.js 文件

  • 基础模型(对象类型和字符串类型)
  • 成功的模型(继承)
  • 失败的模型(继承)
// 基础模型
class BaseModel {
    // data 是对象类型 message 是字符串类型
    constructor(data, message) {
        if (typeof data === 'string') {
            this.message = data
            data = null
            message = null
        }
        if (data) {
            this.data = data
        }
        if (message) {
            this.message = message
        }
    }
}
// 成功模型 errno 赋值 0
class SuccessModel extends BaseModel {
    constructor(data, message) {
        // 继承父类
        super(data, message)
        // 成功的值 0
        this.errno = 0
    }
}
// 失败模型 errno 赋值 -1
class ErrorModel extends BaseModel {
    constructor(data, message) {
        // 继承父类
        super(data, message)
        // 失败的值 -1
        this.errno = -1
    }
}

// 导出共享
module.exports = {
    SuccessModel,
    ErrorModel
}

…/src/router/blog.js 文件

  • 博客相关路由接口
  • 调用相关函数
  • 返回实例
// 导入博客和用户控制器相关内容
const { getList, getDetail, newBlog, updateBlog, delBlog } = require('../controller/blog') 
// 导入成功和失败的模型
const { SuccessModel, ErrorModel } = require('../model/resModel')

// blog 路由
const handleBlogRouter = (req, res) => {
    const method = req.method // GET/POST
    const id = req.query.id // 获取 id

    // 获取博客列表 GET 请求·
    if (method === 'GET' && req.path === '/api/blog/list') {
        // 博客的作者 req.query 用在 GET 请求中
        const author = req.query.author || ''
        // 博客的关键字
        const keyword = req.query.keyword || ''
        // 执行函数 获取博客列表数据
        const listData = getList(author, keyword)

        // 创建并返回成功模型的实例对象
        return new SuccessModel(listData)
    }

    // 获取博客详情 GET 请求
    if (method === 'GET' && req.path === '/api/blog/detail') {
        // 获取博客详情数据
        const data = getDetail(id)
        // 创建并返回成功模型的实例对象
        return new SuccessModel(data)
    }

    // 新建一篇博客 POST 请求
    if (method === 'POST' && req.path === '/api/blog/new') {
        // req.body 用于获取请求中的数据(用在 POST 请求中)
        const data = newBlog(req.body)
        // 创建并返回成功模型的实例对象
        return new SuccessModel(data)
    }

    // 更新一篇博客
    if (method === 'POST' && req.path === '/api/blog/update') {
        // 传递两个参数 id 和 req.body
        const result = updateBlog(id, req.body)
        if (result) {
            return new SuccessModel()
        } else {
            return new ErrorModel('更新博客失败')
        }
    }

    // 删除一篇博客
    if (method === 'POST' && req.path === '/api/blog/delete') {
        const result = delBlog(id)
        if (result) {
            return new SuccessModel()
        } else {
            return new ErrorModel('删除博客失败')
        }
    }
}

// 导出
module.exports = handleBlogRouter

…/src/router/user.js 文件

  • 博客相关路由接口
  • 调用相关函数
  • 返回实例
// 导入用户登录内容
const { loginCheck } = require('../controller/user')
// 导入成功和失败的模板
const { SuccessModel, ErrorModel } = require('../model/resModel')

// user 路由
const handleUserRouter = (req, res) => {
    const method = req.method

    // 登录
    if (method === 'POST' && req.path === '/api/user/login') {
        const { username, password } = req.body
        // 传入两个参数 用户名 密码
        const result = loginCheck(username, password)
        if (result) {
            return new SuccessModel()
        }
        return new ErrorModel('登录失败')
    }
}

// 导出共享
module.exports = handleUserRouter

…/src/controller/blog.js 文件

  • 博客的相关数据处理
  • 返回的是假数据(后续会使用数据库)
// 获取博客列表(通过作者和关键字)
const getList = (author, keyword) => {
    // 先返回假数据(格式是正确的)
    return [{
            id: 1,
            title: '标题1',
            content: '内容1',
            createTime: 1665832332896,
            author: 'zahuopu'
        },
        {
            id: 1,
            title: '标题2',
            content: '内容2',
            createTime: 1665832418727,
            author: 'xiaoming'
        },
    ]
}

// 获取博客详情(通过 id)
const getDetail = (id) => {
    // 先返回假数据
    return {
        id: 1,
        title: '标题1',
        content: '内容1',
        createTime: 1665832332896,
        author: 'zahuopu'
    }
}

// 新建博客 newBlog 若没有,就给它一个空对象
const newBlog = (blogData = {}) => {
    // blogData 是一个博客对象 包含 title content 属性
    console.log('newBlog', blogData)
    return {
        id: 3 // 表示新建博客,插入到数据表里的 id
    }
}

// 更新博客(通过 id 更新)
const updateBlog = (id, blogData = {}) => {
    // id 就是要更新博客的 id
    // blogData 是一个博客对象 包含 title content 属性
    console.log('update blog', id, blogData)
    return true
}

// 删除博客(通过 id 删除)
const delBlog = (id) => {
    return true
}

// 导出共享
module.exports = {
    getList,
    getDetail,
    newBlog,
    updateBlog,
    delBlog
}

…/src/controller/user.js 文件

  • 用户登录的相关数据处理
  • 返回的是假数据(后续会使用数据库)
// 登录(通过用户名和密码)
const loginCheck = (username, password) => {
    // 先使用假数据
    if (username === 'zahuopu' && password === '123') {
        return true
    }
    return false
}

// 导出共享
module.exports = {
    loginCheck
}

三、各个接口的测试

现在我们 已经完成 博客项目的开发了,接下来进入到 测试环节~~

通过关键字和作者 查询博客(GET 请求)

在这里插入图片描述

通过 id 获取 博客详情(GET 请求)

在这里插入图片描述

通过 ApiPost/Postman 工具测试 新增博客(POST 请求)

在这里插入图片描述

通过 ApiPost/Postman 工具测试 更新博客(POST 请求)

在这里插入图片描述

在这里插入图片描述

通过 ApiPost/Postman 工具测试 删除博客(POST 请求)

在这里插入图片描述

通过 ApiPost/Postman 工具测试 登录请求(POST 请求)

在这里插入图片描述

在这里插入图片描述

四、写在最后(附源码)

至此,开发博客的项目(假数据版,并没有使用数据库)就完成了。

后续会对该项目进行多次重构【多种框架(express,koa)和数据库(mysql,sequelize,mongodb)】

如果你需要该项目的 源码,请通过本篇文章最下面的方式 加入 进来~~


在这里插入图片描述


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/405399.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

另一种解决Failed to execute goal on project xxx: Could not resolve dependencies for project com的方法

周青的日常问题记录 项目场景: 学习硅谷电商毕设项目_微服务版本,建站练手。进行到商城前端服务开发的用户服务 store-front-user阶段,pom文件导入依赖报错。 问题描述 报错为 Unresolved dependency: com.atguigu:store-commons:jar:1.0.0…

【 Apifox】Apifox接口设计

Apifox官网地址:http://apifox.cn/a103abcc 文章目录一、接口设计 (接口文档)二、如何定义接口?三、接口路径四、基础信息五、请求参数1.Params 参数2.Body 参数3.Body 参数类型六、参数中使用环境变量(或全局变量/临时变量)七、返…

VSCode中ESLint插件修复+配置教程

文章目录vscodeeslint插件配置教程如果不好用排查1: 如果出现后面回车符问题排查2: 保存时好了但是一瞬间代码又回来了排查3: 右下角是否开启eslint服务排查4: 如果保存还是变回去了排查5: ESLint不生效排查6: 如果都用心走了一遍, 还不行额外说明-新文件还是末尾换行问题vscod…

vue.config.js配置proxy代理解决跨越;proxy代理报404;

像我们本地的vue项目运行起来,访问的地址一般是localhost,这个时候请求后台的接口,端口号也不一致,肯定就会存在跨域问题,所以我们要是想正常访问接口的话,就需要解决掉跨域问题。 本文我们是在vue.config.…

New Promise() 基础

阅读目录console.dir(Promise) 打印resolve 做用reject 的用法catch 的用法all 方法的用法console.dir(Promise) 打印 Promise 是一个构造函数,本身身上有 all、reject、resolve 这几个方法,原型上有 then、catch 等方法。 所以 Promise new 出来的对象…

VUE使用Three.js实现模型,点击交互,相机旋转视角跟随移动(Threejs中使用Tweenjs,含demo源码)

目录 一、Three.js是什么? 二、VUE简单使用Three.js步骤 1.npm安装 2.template模板 3.引入库 4.定义全局变量 5.初始化场景 6.初始化相机 7.初始化灯光 8.初始化渲染器 9.创建模型(这里我搭建的模型是一个简单双面货架模型) 10.根据浏览器窗口自适应 11…

Vue3中slot插槽使用方式

一文搞懂Vue3中slot插槽的使用! 使用 Vue 的小伙伴相信你一定使用过插槽,如果你没有用过,那说明你的项目可能不是特别复杂。插槽(slot)可以说在一个 Vue 项目里面处处都有它的身影,比如我们使用一些 UI 组件…

axios无法加载响应数据:no data found for resource with given identifier

美好的、令人遐想的日落黄昏里,出现了诡异的bug! 老师上课的时候,不好好听听,不仔细看!那么花了那么多时间找bug问题~翻了好多方案,还未解决,然后遇到了我,这个大冤种就是你&#xf…

EasyExcel解析动态表头及导出

前言 excel文件导入及导出,是日常开发中经常遇到的需求。本次笔者以EasyExcel为例,针对在项目中遇到的动态表头解析及导出的场景,详细介绍具体的代码实现过程。 参考地址 https://github.com/alibaba/easyexcel 前端下载 const download …

JavaScript判断对象是否为空对象的几种方法

目录 1、空对象对应的字符串为 "{}" 2、for in 3、jquery 的 isEmptyObject()方法 4、Object.getOwnPropertyNames() 5、ES6 的 Object.keys() JSON.stringify()扩展 1、第一大特性 小结 2、第二大特性 3、第三大特性 4、第四大特性 5、第五大特性 6、第…

Vue实战——使用代理服务器解决跨域问题——No‘Access-Control-Allow-Origin‘ header is present on the requested resource

概论: 目录 一、跨域问题是怎么产生的 1.1 跨域问题: 1.2 解决办法 三、开启代理服务器 第一种方式:(存在弊端) 细节问题:(解释两个弊端) 第二种方式:&#xff08…

el-input设置必填提示(单个多个)

有两种:一种是多个el-input通过同一个el-form表单来限制,这种用得最多的地方就是添加和修改功能;另一种是每个el-input通过各自的el-form表单来限制,这种通常是用在动态添加多个输入框等功能上,话不多说,上才艺噻. 第一种(多个el-input同时限…

【JavaScript】JS实用案例分享:DOM节点转JSON数据 | 标签输入框

🖥️ NodeJS专栏:Node.js从入门到精通 🖥️ 博主的前端之路(源创征文一等奖作品):前端之行,任重道远(来自大三学长的万字自述) 🖥️ TypeScript知识总结&…

微信小程序--》tabBar底部栏

🏍️作者简介:大家好,我是亦世凡华、渴望知识储备自己的一名在校大学生 🛵个人主页:亦世凡华、 🛺系列专栏:微信小程序 🚲座右铭:人生亦可燃烧,亦可腐败&…

搭建博客,基于vue3 的 vitepress 轻松搞定

Ⅰ、什么是vitepress 💎 vitepress 使用场景 简单的说 ,只要 会用 markdown 语法,就能构建自己的 「博客、笔记、使用文档」等系统 ; ✨ vitepress 优势 优势介绍傻瓜式操作只需要配置 菜单 和 对应的 markdown 就能实现博客、笔…

【Vue脚手架安装教程】

文章目录前言一、安装Node.js二、配置淘宝镜像安装cnpm,将npm设置为淘宝镜像:二、安装vue/cli检查是否安装成功: vue -V 或者 vue --version ![在这里插入图片描述](https://img-blog.csdnimg.cn/7f66366eba81456388fcf28871db0650.png)三、 创建一个vue…

Chrome浏览器的跨域设置

做前后端分离的开发的时候,出于一些原因往往需要将浏览器设置成支持跨域的模式,而且chrome浏览器支持可跨域的设置,但是新版本的chrome浏览器提高了跨域设置的门槛,原来的方法不再适用了。其实网上也有很多大神总结的chrome跨域设…

webpack的面试题(吐血整理)

以下为整理的webpack面试题,如有不足之处,还请大家多多指正。 一、webpack的构建流程 二、对webpack的理解 webpack是一个打包模块化js的工具,在webpack里一切文件皆模块,通过loader转换文件,通过plugin注入钩子&#…

最常见的六种跨域解决方案

目录: 前言:什么是跨域?JSONPCORS搭建Node代理服务器Nginx反向代理postMessageWebsocket总结 前言:什么是跨域? 跨域就是当在页面上发送ajax请求时,由于浏览器同源策略的限制,要求当前页面和…

jQuery模态弹窗插件(jquery-confirm)

前言 今天为大家分享一款开源的非常轻量且精美的jQuery模态弹窗插件:jquery-confirm,它包含Bootstrap,Material等多种主题供选择。 如果你的前端项目中还在使用jQuery,那么jquery-confirm是你模态弹窗的完美选择。 下面我们就来零距离感受…