项目简介

本文适用哪些人?有开发经验,熟悉MySQL,熟悉JavaScript,熟悉Vue,本文参考:@CSDN@知乎@博客

为什么用Node.js作为后端(个人)?

最近吧,在某B直聘刷刷工作机会,然后刷到一些岗位关键词,web全栈开发工程师,大专,14薪,20K起步,3-5年工作经验?emmmmmm这要求不高,薪资待遇又还阔以,挺心动的😍😍😍😍!!!于是点击去查看,公司在珠海的,看着图片啊,岗位什么的啊,感觉都还不错。于是投简历试试!
和面试官简单沟通,前面挺好的,后面问到能独立开发吗?我:当然能(毕竟之前小公司的全栈那都是往死里压榨,什么都要会😭)。然后问我能用node独立部署应用吗?我当时觉得也就是npm打些包之类的(理解太浅)。然后又问我一些Express/Koa啊之类的东西,这时我才发现草率了啊,这人是来砸场子的吧👿👿
web全栈常见选型不是vue+php或者vue+java之类的吗?在这之前我用node也只是简单的npm大法而已,还能用作后端?这对于我来说无疑是让陈晓琪接替达摩院啊!杀牛用鸡刀啊?啊对了,陈晓琪是我的ZZ同事…好吧,到此我也没当回事,直到第二天我又刷到一个需要用nodejs做后端的招娉,待遇也同样不错,然后好奇心之下使我们在此相遇😶

为什么用Node.js作为后端(企业)?

百度大法 -> 来自@知乎@博客

  1. 事件驱动:Node.js的设计思想中以事件驱动为核心,它提供的绝大多数API都是基于事件的、异步的风格。
    在这里插入图片描述
    事件驱动的优势在于充分利用了系统资源,执行代码无须阻塞等待某种操作完成,有限的资源可以用于其他任务。在服务器开发中,并发的请求处理是一个大问题,阻塞式的函数会导致资源浪费和事件延迟。通过事件注册、异步函数,开发人员可以提高资源的利用率,性能也会改善。

  2. 异步、非阻塞I/O:在Node.js提供的支持模块中,包括文件操作在内的许多函数都是异步执行的。同时为了方便服务器开发,Node.js的网络模块特别多,包括HTTP、DNS、NET、UDP、HTTPS、TLS等。开发人员可以在此基础上快速构建Web服务器。
    在这里插入图片描述

这是最重要的两点,还有好多其他的,懒得写(抄)了,总之:

优点:

  1. 高并发(最重要的优点)
  2. 适合I/O密集型应用

缺点:

  1. 不适合 CPU 密集型应用
    CPU 密集型应用给 Node 带来的挑战主要是:由于 JavaScript 单线程的原因,如果有长时间运行的计算(比如大循环),将会导致 CPU 时间片不能释放,使得后续 I/O 无法发起;
  2. 只支持单核CPU,不能充分利用CPU;
  3. 可靠性低,一旦代码某个环节崩溃,整个系统都崩溃;
     原因:单进程,单线程;
     解决方案:(1)Nnigx反向代理,负载均衡,开多个进程,绑定多个端口;(2)开多个进程监听同一个端口,使用cluster模块;
  4. 开源组件库质量参差不齐,更新快,向下不兼容;
  5. Debug不方便,错误没有stack trace;

适合的使用场景

  1. 敏捷开发
    快速、轻量、低成本、前端开发者友好。

  2. RESTful API
    这是 NodeJS 最理想的应用场景,可以处理数万条连接,本身没有太多的逻辑,只需要请求API,组织数据进行返回即可。它本质上只是从某个数据库中查找一些值并将它们组成一个响应。由于响应是少量文本,入站请求也是少量的文本,因此流量不高,一台机器甚至也可以处理最繁忙的公司的API需求。

  3. 统一 Web 应用的 UI 层
    3目前 MVC 的架构,在某种意义上来说,Web 开发有两个 UI 层,一个是在浏览器里面我们最终看到的,另一个在 server 端,负责生成和拼接页面。不讨论这种架构是好是坏,但是有另外一种实践,面向服务的架构,更好的做前后端的依赖分离。如果所有的关键业务逻辑都封装成 REST 调用,就意味着在上层只需要考虑如何用这些REST 接口构建具体的应用。那些后端程序员们根本不操心具体数据是如何从一个页面传递到另一个页面的,他们也不用管用户数据更新是通过 Ajax 异步获取的还是通过刷新页面。

  4. 大量 Ajax 请求的应用
    例如个性化应用,每个用户看到的页面都不一样,缓存失效,需要在页面加载的时候发起 Ajax 请求,NodeJS 能响应大量的并发请求。

  5. 适合I/O密集型的应用
    总而言之,Node.js适合运用在高并发、I/O密集、少量业务逻辑的场景。代表性的有:网站开发、前端构建工具、api调用服务、高I/O服务。
    其实 Node.js能实现几乎一切的应用,我们考虑的点只是适不适合用它来做。

开发环境准备

不会安装方法的麻烦自己百度一下,我的本来就装好了的哈哈哈哈哈哈哈哈哈哈😄

安装Node.js

下载地址:@Node.js
我的版本是:v14.19.3
在这里插入图片描述

安装MySQL数据库

下载地址:@MySQL
我的是5.7.18版本,建议5.8,我懒就不换了😪
在这里插入图片描述

安装Navicat Premium (可选)

数据库可视化软件,自行选择,不装就黑窗口查数据吧!
下载地址:自己百度哈(因为🌳🌳🌳🌳…)
我的版本是16
在这里插入图片描述

安装Idea:HBuilder X(可选其他)

下载地址:@HBuilder X
我的版本:2023-11-07最新版
在这里插入图片描述

项目结构

新建项目

打开idea,新建项目-普通项目-Node项目,项目名称是:node_service
在这里插入图片描述

这是第一步创建后的项目结构

检查npm和cnpm

打开终端CMD,进入到node_service目录
在这里插入图片描述

检查npmcnpm(可选)是否安装,没装的要去安装一下,新版是自带npm的,cnpm的作用相当于npm镜像加速下载之类的,以下安装模块都用cnpm,不装的话就使用npm命令

npm -v
cnpm -v

在这里插入图片描述

安装依赖模块

  1. 安装 Node.js 的 mysql 驱动
    在终端运行:

    cnpm install mysql
    

    在这里插入图片描述
    这样就表示安装成功

  2. 安装 Express 框架
    Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用,和丰富的 HTTP 工具,使用 Express 可以快速地搭建一个完整功能的网站

    Express 框架核心特性:

    • 可以设置中间件来响应 HTTP 请求。
    • 定义了路由表用于执行不同的 HTTP 请求动作。
    • 可以通过向模板传递参数来动态渲染 HTML 页面。
    cnpm install express --save
    

    在这里插入图片描述

  3. 安装 body-parser 模块

    body-parser用于处理 JSON, Raw, Text 和 URL 编码的数据。

    cnpm install body-parser --save
    

    在这里插入图片描述

  4. 安装 cookie-parser 模块(可选)
    这就是一个解析Cookie的工具。通过req.cookies可以取到传过来的cookie,并把它们转成对象

    cnpm install cookie-parser --save
    

    在这里插入图片描述

  5. 安装 multer 模块(可选)
    用于处理 enctype=“multipart/form-data”(设置表单的MIME编码)的表单数据,它主要用于上传文件。

    cnpm install multer --save
    

    在这里插入图片描述

  6. 安装 silly-datetime 模块(可选)
    他的功能主要是格式化时间

    cnpm i silly-datetime --save
    

    在这里插入图片描述

  7. 安装 nodemon 模块
    nodemon 是一种工具,可在检测到目录中的文件更改时通过自动重新启动节点应用程序来帮助开发基于 node.js 的应用程序。一般只在开发时使用,它最大的长处在于 watch 功能,一旦文件发生变化,就自动重启进程。
    特性:

    • 自动重新启动应用程序。
    • 检测要监视的默认文件扩展名。
    • 默认支持 node,但易于运行任何可执行文件,如 python、ruby、make 等。
    • 忽略特定的文件或目录。
    • 监视特定目录。
    • 使用服务器应用程序或一次性运行实用程序和 REPL。
    • 可通过 Node require 语句编写脚本。
    • 开源,在 github 上可用。
    cnpm i -D nodemon
    

    在这里插入图片描述
    打开项目目录下的package.json文件,在scripts下增加一行

    "dev": "nodemon index.js"
    

    在这里插入图片描述

完全体比对

在这里插入图片描述

Hello World!

本章完成项目配置并输出Hello World!

新建入口文件

在项目根目录下新建 index.js 文件,这个文件对应上一步 package.json 文件里面的 nodemon index.js
在这里插入图片描述

编辑 index.js 文件

const fs = require('fs');
const path = require('path');
 
// 引入api路由配置文件
const api = require('./config/api');
 
// body-parser - node.js 中间件,用于处理 JSON, Raw, Text 和 URL 编码的数据
const bodyParser = require('body-parser');
 
// 引入express包
const express = require('express');
 
// 创建web服务器
const app = express();
 
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
 
// 后端api路由
app.use('/api', api);
 
// 监听端口
app.listen(3000);
// 在终端打印信息
console.log('success listen at port: 3000......');

在这里插入图片描述

数据库配置

在根目录下创建 config 目录,在config目录下新建 db.js 文件
在这里插入图片描述
编辑 db.js 文件,和本地安装的MySQL配置一样

// 数据库连接配置
module.exports = {
	mysql: {
		host: 'localhost', // 主机地址 (默认:localhost)
		user: 'root', // 数据库用户名
		password: '123456', // 数据库密码
		database: 'node_user', // 数据库名
		port: '3306' // 端口号 (默认:3306)
	}
}

在这里插入图片描述

新建数据库 node_user,我用的是 utf8mb4 字符集
在这里插入图片描述

API配置

config 目录下新建 api.js 文件
在这里插入图片描述

编辑 api.js 文件

// 引入数据库连接配置
var models = require('./db');
// 引入express包
var express = require('express');
 
//创建路由器对象
var router = express.Router();
// 引入mysql包
var mysql = require('mysql');
 
// 格式化时间模块Silly-datetime
var datetime = require('silly-datetime');
 
var fs = require('fs');
var path = require('path')
 
// 连接数据库
var conn = mysql.createConnection(models.mysql);
conn.connect();
 
// 设置返回response
var jsonWrite = function (res, ret) {
    if (typeof ret === 'undefined') {
        res.json({
            code: '1',
            msg: '操作失败'
        });
    } else {
        console.log('ret', ret)
        res.json(ret);
    }
};
 
 
// 下面是api路由的代码
router.get('/xxx', (req, res) => {
    // ...
})
 
router.post('/hello', (req, res) => {
    // ...
	jsonWrite(res, {
		code: 200,
		msg: "Hello World!"
	})
})

// 导出路由对象
module.exports = router;


在这里插入图片描述

运行服务

进入cmd终端运行启动命令,这命令指向package.json->scripts->dev

npm run dev

在这里插入图片描述
在这里插入图片描述
当显示监听3000端口则表示启动成功了,想退出则使用快捷键 Ctrl + C

调用 hello 接口

通过api调用工具调用接口
在这里插入图片描述
这个过程发生了什么?

  • 工具使用POST方式调用了本地的 http://127.0.0.1:3000/api/hello 接口
  • 端口号 3000 是我们 index.js 里配置的app.listen(3000),前缀 /api 是我们 index.js 里配置的 app.use(‘/api’, api)hello 则是我们在 /config/api.js 里面的 router.post(‘/hello’)
  • 返回值 “code”: 200,“msg”: “Hello World!” 则是接口封装的信息
    在这里插入图片描述
    在这里插入图片描述

调用 getUserName 接口

新增数据库表

node_user 数据库新建表,运行以下sql语句,会在数据库生成一张user表,结构只有简单的id和name两个字段

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, '张三');
INSERT INTO `user` VALUES (2, '李四');

SET FOREIGN_KEY_CHECKS = 1;

在这里插入图片描述
在这里插入图片描述

编写接口

打开 /config/api.js 文件并编辑内容,直接保存然后会自动更新,不用退出重启应用

router.get('/getUserName', (req, res) => {
	conn.query("select * from user", function(err, result) {
		if (err) {
			console.log(err);
		}

		if (result) {
			jsonWrite(res, result);
		}
	})
})

在这里插入图片描述
调用接口获得返回值
在这里插入图片描述
这个过程发生了什么?

  • 工具使用 GET 方式调用了本地的 http://127.0.0.1:3000/api/getUserName 接口
  • 端口号 3000 是我们 index.js 里配置的app.listen(3000),前缀 /api 是我们 index.js 里配置的 app.use(‘/api’, api)getUserName 则是我们在 /config/api.js 里面的 router.get(‘/getUserName’)
  • 在 getUserName 接口里,我们执行了 conn.query(“select * from user”), conn 是我们的数据库连接信息,这里可以理解为在数据库执行了sql语句 select * from user
  • 返回值是一个数组,1->张三,2->李四,对应数据里user表的数据

调用 getUserNameById 接口

打开 /config/api.js 文件并编辑内容,直接保存然后会自动更新,不用退出重启应用

router.post('/getUserNameById', (req, res) => {
	let params = req.body;
	conn.query("select * from user where id = ?", [params.id], function(err, result) {
		if (err) {
			console.log(err);
		}

		if (result) {
			jsonWrite(res, result);
		}
	})
})

在这里插入图片描述
调用接口获得返回值
在这里插入图片描述
这个过程发生了什么?

  • 工具使用 POST 方式调用了本地的 http://127.0.0.1:3000/api/getUserNameById 接口
  • 端口号 3000 是我们 index.js 里配置的app.listen(3000),前缀 /api 是我们 index.js 里配置的 app.use(‘/api’, api),**getUserNameById ** 则是我们在 /config/api.js 里面的 router.post('/getUserNameById ')
  • 在 getUserNameById 接口里,我们执行了conn.query(“select * from user where id = ?”, [params.id]),增加了 where 条件
  • params是我们请求的入参,以 json 的方式入参名为 id,值是1
  • 返回值是一个数组,1->张三,对应数据里user表主键id为1的数据

总结

优点:简单体验一下真的很敏捷很快😮😮,三两下就跑起来了,很轻量,对前端比较友好,补充一些数据库经验就可以尝试后端入门了。
缺点:感觉整体结构不健壮,随着服务增多导致不容易维护,也可能是我入门的原因吧,真实战还得上github找一些成熟开源项目,看一下别人的结构是怎样的。

好了,已经学会扭螺丝了,可以准备造火箭了😊

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐