草庐IT

Nodejs后端架构基础知识和案例展示

IT飞牛 2023-11-10 原文

入门笔记,大神请绕路!!!
简单的说 Node.js 就是运行在服务端的 JavaScript。
Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台。
Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好。

NodeJS的优缺点

  • 优点:
    1.高并发(高并发的时候,会出现数据库连接数不够用的情况,网上还有对应解决方案,还未实践)
    2.适合I/O密集型应用
    3.事件驱动、非阻塞I/O、高效、轻量

解决数据库高并发,程序解决方案:
数据库高并发时,连接数不够。平台监听sql操作,如果状态是ready,就回调执行sql操作。相当于将sql操作也做异步回调处理,每次sql操作都是在上次操作ready后,再执行,强制串行执行sql操作。这样就减轻数据库压力。但是也可能导致整个应用变慢。

var proxy = new EventProxy();
var status = "ready";
var select = function(callback){
    proxy.once("selected",callback);
    if(status == "ready"){
        status = "pending";
        db.select("SQL", function(results){
            proxy.emit("selected",results);
            status = "ready";
        });
    }
  • 缺点:
    1.不适合CPU密集型应用;
    CPU密集型应用给Node带来的挑战主要是:由于JavaScript单线程的原因,如果有长时间运行的计算(比如大循环),将会导致CPU时间片不能释放,使得后续I/O无法发起;
    解决方案:分解大型运算任务为多个小任务,使得运算能够适时释放,不阻塞I/O调用的发起;
    2.只支持单核CPU,不能充分利用CPU(可以利用多进程利用cpu的,cluster就可以让你做到nodejs将电脑多核利用起来)解决方案:
    (1)Nnigx反向代理,负载均衡,开多个进程,绑定多个端口;
    (2)开多个进程监听同一个端口,使用cluster模块;

应用场景

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

2. 统一Web应用的UI层
目前MVC的架构,在某种意义上来说,Web开发有两个UI层,一个是在浏览器里面我们最终看到的,另一个在server端,负责生成和拼接页面。

不讨论这种架构是好是坏,但是有另外一种实践,面向服务的架构,更好的做前后端的依赖分离。如果所有的关键业务逻辑都封装成REST调用,就意味着在上层 只需要考虑如何用这些REST接口构建具体的应用。那些后端程序员们根本不操心具体数据是如何从一个页面传递到另一个页面的,他们也不用管用户数据更新是 通过Ajax异步获取的还是通过刷新页面。

3. 大量Ajax请求的应用

例如个性化应用,每个用户看到的页面都不一样,缓存失效,需要在页面加载的时候发起Ajax请求,NodeJS能响应大量的并发请求。总而言之,NodeJS适合运用在高并发、I/O密集、少量业务逻辑的场景。

演示一:Hello World!

脚本模式
以下是我们的第一个Nodejs程序:

console.log("Hello World");

保存该文件,文件名为 helloworld.js, 并通过 node命令来执行:node helloworld.js。程序执行后,正常的话,就会在终端输出 Hello World

image.png

交互模式
打开终端,键入node进入命令交互模式,可以输入一条代码语句后立即执行并显示结果,例如:

$ node
> console.log('Hello World!');
Hello World!

image

演示二:nodejs基于http插件,监听接口,返回数据

1、新建app.js文件,然后并执行执行node app.js
代码如下:

var http = require('http');
var server = http.createServer(function (req, res) {
    var body = '';
    req.on('data', function(data) {      // 接收客户端发送过来的数据, 也就是 xmlHttp.send(value);
        body += data;
    });

    req.on('end', function() {
        res.writeHeader(200, {
            'Content-Type': 'text/plain',
            'Access-Control-Allow-Origin': '*'    //解决跨域问题
        });
        res.write("hello:" + body);
        res.end();
    })
});
server.listen(3000, function () {
    console.log('server start at localhost:3000');
});

2、找个引入jquery的页面,执行post请求:

$.ajax({
url:"http://localhost:3000",
data:"我是快递小哥,请开开门",
type:"post",
success:function(d){console.log("success",d)},
error:function(d){console.log("error",d)}
})

执行请求,返回hello:我是快递小哥,请开开门

image.png

这个例子中,nodejs充当后台,app.js中实现了http://loadlhost:3000接口,返回了前端提交的内容。

演示三:nodejs基于express插件,监听接口,返回数据

1、新建service.js文件,然后执行执行node service.js
代码如下:

//demo
const express = require('express');
const app = express();

//设置允许跨域访问该服务.
app.all('*', function (req, res, next) {
  res.header('Access-Control-Allow-Origin', '*');
  //Access-Control-Allow-Headers ,可根据浏览器的F12查看,把对应的粘贴在这里就行
  res.header('Access-Control-Allow-Headers', 'Content-Type');
  res.header('Access-Control-Allow-Methods', '*');
  res.header('Content-Type', 'application/json;charset=utf-8');
  next();
});

app.post('/hello', function (req, res) {
  res.json({title:"你好"});
  
});

const server = app.listen(8082, function () {
  console.log('Express app server listening on port %d', server.address().port);
});

2、找个引入jquery的页面,执行post请求:

$.ajax({
url:"http://localhost:8082/hello",
type:"post",
success:function(d){console.log("success",d)},
error:function(d){console.log("error",d)}
})

返回数据:

image.png

演示四:nodejs+express+mysql搭建后端环境

引用:http://www.cnblogs.com/ssqqhh/p/6289690.html1、创建数据库
创建名为nodejs的数据库,新建一张users表,采用utf8编码。表结构和数据如下:

image.png
2、安装express
npm i express -g//安装express
npm i express-generator -g//安装命令行工具
express --version//检测express是否安装成功

3、创建express项目
执行express express-demo,新建express项目,文件目录说明:

app.js//启动文件,或者说入口文件。新的页面以及页面相应的路由需要在这里配置;
package.json//存储着工程的信息及模块依赖,当在 dependencies 中添加依赖的模块时,运行 npm install,npm //会检查当前目录下的 package.json,并自动安装所有指定的模块
node_modules//存放 package.json 中安装的模块,当你在 package.json 添加依赖的模块并安装后,存放在这个文件夹下
public//存放 image、css、js 等文件
routes//存放路由文件
views//存放视图文件或者说模版文件
bin//存放可执行文件

4、运行express项目

cd express-demo//进入项目
npm i//安装依赖文件
npm start//启动项目

启动成功,空荡荡的页面中就出现下面内容

image.png
5、写项目代码
需要创建以下文件: model\config.js:数据库配置
module.exports = {
    mysql: {
        host: 'localhost',
        user: 'root',
        password: '123123',
        database: 'nodejs',
        port: 3306
    }
};

views\login.jade:登录页面

doctype html
html
  head
    title
    link(href='/stylesheets/style.css', rel='stylesheet')
    link(href='/bootstrap-3.3.7/css/bootstrap.min.css', rel='stylesheet')
    script(src='/javascripts/jquery.min.js')
    script(src='/bootstrap-3.3.7/js/bootstrap.min.js')
  body(style='background: #dcd9da')
    // h1= title
    .container
      .row
        .col-md-4.col-md-offset-4
          .panel.panel-default(style='margin-top: 100px')
            .panel-heading(style='background: #0d6aad')
              h4(align='center', style='color: #ffffff;')
                | express-jade-bootstrap-mysql-demo
            .panel-body(style='background: #e0e1ea')
              .form-group
                .input-group
                  span.input-group-addon 账号
                  input#username.form-control(type='text', placeholder='请输入账号')
              .form-group
                .input-group
                  span.input-group-addon 密码
                  input#password.form-control(type='password', placeholder='请输入密码')
              .form-group
                .col-lg-offset-7
                  | 没有账号?
                  a(href='/register') 注册
              .form-group
                button#login.btn.btn-success.btn-block(type='button')
                  | 登录
              #popup.alert.alert-warning
                a#close.close(href='#') ×
                div(align='center')
                  strong#popup-content(style='color: #b12e30;')
    script(type='text/javascript').
      $(document).ready(function () {
        var username = $("#username");
        var password = $("#password");
        var login = $("#login");
        var popup = $("#popup");
        var popupContent = $("#popup-content");
        var close = $("#close");
        popup.hide();
        close.click(function () {
          popup.hide();
        });
        login.click(function () {
          if (username.val() == "" || password.val() == "") {
            popup.show();
            popupContent.html("账号或密码不能为空!");
          } else {
            $.ajax({
                      url: "/login/userLogin",
                      data: {
                        username: $("#username").val(),
                        password: $("#password").val()
                      },
                      type: "POST",
                      timeout: 36000,
                      dataType: "text",
                      success: function (data, textStatus) {
                        //alert(data);
                        var dataJson = eval("(" + data + ")");
                        if (dataJson.code == 200) {
                          alert("登录成功");
                          window.location.href = "/";
                        } else if (dataJson.code == 300) {
                          popup.show();
                          popupContent.html("账号不存在,请重新输入!");
                        } else if (dataJson.code == 400) {
                          popup.show();
                          popupContent.html("密码有误,请重新输入!");
                        } else {
                          popup.show();
                          popupContent.html("登录出错!");
                        }
                      },
                      error: function (XMLHttpRequest, textStatus, errorThrown) {
                        alert("error:" + textStatus);
                      }
                    }
            );
          }
        })
        ;
      })
      ;

routes\login.js:登录接口逻辑

var express = require('express');
var router = express.Router();
// 实现与MySQL交互
var mysql = require('mysql');
var config = require('../model/config');
// 使用连接池,提升性能
var pool = mysql.createPool(config.mysql);
/* GET home page. */
router.get('/', function (req, res, next) {
    res.render('login', { title: 'login' });
});
router.post('/userLogin', function (req, res, next) {
    var username = req.body.username;//获取前台请求的参数
    var password = req.body.password;
    pool.getConnection(function (err, connection) {
        //先判断该账号是否存在
        var $sql = "select * from users where username=?";
        connection.query($sql, [username], function (err, result) {
            var resultJson = result;
            console.log(resultJson.length);
            if (resultJson.length === 0) {
                result = {
                    code: 300,
                    msg: '该账号不存在'
                };
                res.json(result);
                connection.release();
            } else {  //账号存在,可以登录,进行密码判断
                var $sql1 = "select password from users where username=?";
                connection.query($sql1, [username], function (err, result) {
                    var temp = result[0].password;  //取得数据库查询字段值
                    console.log(temp);
                    if (temp == password) {
                        result = {
                            code: 200,
                            msg: '密码正确'
                        };
                    } else {
                        result = {
                            code: 400,
                            msg: '密码错误'
                        };
                    }
                    res.json(result); // 以json形式,把操作结果返回给前台页面
                    connection.release();// 释放连接
                });
            }
        });
    });
});
module.exports = router;

views\register.jade:注册页面

doctype html
html
  head
    title
    link(href='/bootstrap-3.3.7/css/bootstrap.min.css', rel='stylesheet')
    script(src='/javascripts/jquery.min.js')
    script(src='/bootstrap-3.3.7/js/bootstrap.min.js')
  body(style='background: #dcd9da')
    nav.collapse.navbar-collapse.navbar-inverse
      .navbar-header
        a.navbar-brand express-jade-bootstrap-mysql-demo
      ul.nav.navbar-nav.navbar-right
        li(style='margin-right: 20px')
          a(href='/login')
            span.glyphicon.glyphicon-log-in
            |  登录
    .container
      .row
        .col-md-4.col-md-offset-4
          .panel.panel-default(style='margin-top: 40px')
            .panel-heading(style='background: #0d6aad')
              h3(align='center', style='color: #ffffff;')
                | 账号注册
            .panel-body(style='background: #e0e1ea')
              .form-group
                .input-group
                  span.input-group-addon   账   号  
                  input#username.form-control(type='text', placeholder='请输入账号')
              .form-group
                .input-group
                  span.input-group-addon   密   码  
                  input#password.form-control(type='password', placeholder='请输入密码')
              .form-group
                .input-group
                  span.input-group-addon 确认密码
                  input#password1.form-control(type='password', placeholder='请再次输入密码')
              .form-group
                .input-group
                  span.input-group-addon   姓   名  
                  input#name.form-control(type='text', placeholder='请输入姓名')
              .form-group
                button#register.btn.btn-success.btn-block(type='button')
                  | 注册
              #popup.alert.alert-warning
                a#close.close(href='#') ×
                div(align='center')
                  strong#popup-content(style='color: #b12e30;')
    script(type='text/javascript').
      $(document).ready(function () {
        var username = $("#username");
        var password = $("#password");
        var password1 = $("#password1");
        var name = $("#name");
        var register = $("#register");
        var popup = $("#popup");
        var popupContent = $("#popup-content");
        var close = $("#close");
        popup.hide();
        close.click(function () {
          popup.hide();
        });
        register.click(function () {
          if (username.val() == "" || password.val() == "" || password1.val() == "" || name.val() == "") {
            popup.show();
            popupContent.html("注册信息不能为空!");
          } else if (password.val() !== password1.val()) {
            popup.show();
            popupContent.html("两次输入的密码不一样!");
          } else {
            //访问服务器,将注册信息写入数据库
            $.ajax({
              url: "/register/userRegister",
              data: {
                username: $("#username").val(),
                password: $("#password").val(),
                name: $("#name").val()
              },
              type: "POST",
              timeout: 36000,
              dataType: "text",
              success: function (data, textStatus) {
                var dataJson = eval("(" + data + ")");
                if (dataJson.code == 200) {
                  alert("注册成功");
                  window.location.href = "/login";
                } else if (dataJson.code == 300) {
                  popup.show();
                  popupContent.html("该账号已存在!");
                } else if (dataJson.code == 400) {
                  popup.show();
                  popupContent.html("注册失败,请重新注册!");
                } else {
                  popup.show();
                  popupContent.html("注册出错!");
                }
              },
              error: function (XMLHttpRequest, textStatus, errorThrown) {
                alert("error:" + textStatus);
              }
            });
          }
        });
      });

routes\register.js:注册接口逻辑

var express = require('express');
var router = express.Router();
// 实现与MySQL交互
var mysql = require('mysql');
var config = require('../model/config');
// 使用连接池,提升性能
var pool = mysql.createPool(config.mysql);
/* GET home page. */
router.get('/', function (req, res, next) {
    res.render('register', { title: 'register' });
});
router.post('/userRegister', function (req, res, next) {
    var username = req.body.username;
    var password = req.body.password;
    var name = req.body.name; //获取前台请求的参数
    pool.getConnection(function (err, connection) {
        //先判断该账号是否存在
        var $sql = "select * from users where username=?";
        connection.query($sql, [username], function (err, result) {
            var resultJson = result;
            console.log(resultJson.length);
            if (resultJson.length !== 0) {
                result = {
                    code: 300,
                    msg: '该账号已存在'
                };
                res.json(result);
                connection.release();
            } else {  //账号不存在,可以注册账号
                // 建立连接,向表中插入值  数据库表名为user-info会出错
                var $sql1 = "INSERT INTO users(id, username, password, name) VALUES(0,?,?,?)";
                connection.query($sql1, [username, password, name], function (err, result) {
                    console.log(result);
                    if (result) {
                        result = {
                            code: 200,
                            msg: '注册成功'
                        };
                    } else {
                        result = {
                            code: 400,
                            msg: '注册失败'
                        };
                    }
                    res.json(result); // 以json形式,把操作结果返回给前台页面
                    connection.release();// 释放连接
                });
            }
        });
    });
});
module.exports = router;

app.js:修改代码

...
var login = require("./routes/login");
var register = require("./routes/register");
...
app.use('/login', login);
app.use('/register', register);
...

jquery.min.js:引入jquery,放到public文件夹bootstrap:引入bootstrap,放到public文件夹

准备好以上代码后,执行npm start命令启动项目,打开登录页面:http://localhost:3000/login,注册页面:http://localhost:3000/register

登陆成功
注册成功


参考: NodeJs+Express+SqlServer简易后台API服务搭建

有关Nodejs后端架构基础知识和案例展示的更多相关文章

  1. 「Python|Selenium|场景案例」如何定位iframe中的元素? - 2

    本文主要介绍在使用Selenium进行自动化测试或者任务时,对于使用了iframe的页面,如何定位iframe中的元素文章目录场景描述解决方案具体代码场景描述当我们在使用Selenium进行自动化测试的时候,可能会遇到一些界面或者窗体是使用HTML的iframe标签进行承载的。对于iframe中的标签,如果直接查找是无法找到的,会抛出没有找到元素的异常。比如近在咫尺的例子就是,CSDN的登录窗体就是使用的iframe,大家可以尝试通过F12开发者模式查看到的tag_name,class_name,id或者xpath来定位中的页面元素,会抛出NoSuchElementException异常。解决

  2. postman接口测试工具-基础使用教程 - 2

    1.postman介绍Postman一款非常流行的API调试工具。其实,开发人员用的更多。因为测试人员做接口测试会有更多选择,例如Jmeter、soapUI等。不过,对于开发过程中去调试接口,Postman确实足够的简单方便,而且功能强大。2.下载安装官网地址:https://www.postman.com/下载完成后双击安装吧,安装过程极其简单,无需任何操作3.使用教程这里以百度为例,工具使用简单,填写URL地址即可发送请求,在下方查看响应结果和响应状态码常用方法都有支持请求方法:getpostputdeleteGet、Post、Put与Delete的作用get:请求方法一般是用于数据查询,

  3. 软件测试基础 - 2

    Ⅰ软件测试基础一、软件测试基础理论1、软件测试的必要性所有的产品或者服务上线都需要测试2、测试的发展过程3、什么是软件测试找bug,发现缺陷4、测试的定义使用人工或自动的手段来运行或者测试某个系统的过程。目的在于检测它是否满足规定的需求。弄清预期结果和实际结果的差别。5、测试的目的以最小的人力、物力和时间找出软件中潜在的错误和缺陷6、测试的原则28原则:20%的主要功能要重点测(eg:支付宝的支付功能,其他功能都是次要的)80%的错误存在于20%的代码中7、测试标准8、测试的基本要求功能测试性能测试安全性测试兼容性测试易用性测试外观界面测试可靠性测试二、质量模型衡量一个优秀软件的维度①功能性功

  4. ES基础入门 - 2

    ES一、简介1、ElasticStackES技术栈:ElasticSearch:存数据+搜索;QL;Kibana:Web可视化平台,分析。LogStash:日志收集,Log4j:产生日志;log.info(xxx)。。。。使用场景:metrics:指标监控…2、基本概念Index(索引)动词:保存(插入)名词:类似MySQL数据库,给数据Type(类型)已废弃,以前类似MySQL的表现在用索引对数据分类Document(文档)真正要保存的一个JSON数据{name:"tcx"}二、入门实战{"name":"DESKTOP-1TSVGKG","cluster_name":"elasticsear

  5. ruby - Ruby 和 Ruby on Rails 中的三层架构 - 2

    我是一名决定学习Ruby和RubyonRails的ASP.NETMVC开发人员。我已经有所了解并在RoR上创建了一个网站。在ASP.NETMVC上开发,我一直使用三层架构:数据层、业务层和UI(或表示)层。尝试在RubyonRails应用程序中使用这种方法,我发现没有关于它的信息(或者也许我只是找不到它?)。也许有人可以建议我如何在RubyonRails上创建或使用三层架构?附言我使用ruby​​1.9.3和RubyonRails3.2.3。 最佳答案 我建议在制作RoR应用程序时遵循RubyonRails(RoR)风格。Rails

  6. ruby - 我怎样才能更好地了解/了解更多关于 Ruby 的知识? - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我最近开始学习Ruby,这是我的第一门编程语言。我对语法感到满意,并且我已经完成了许多只教授相同基础知识的教程。我已经写了一些小程序(包括我自己的数组排序方法,在有人告诉我谷歌“冒泡排序”之前我认为它非常聪明),但我觉得我需要尝试更大更难的东西来理解更多关于Ruby.关于如何执行此操作的任何想法?

  7. 【网络】-- 网络基础 - 2

    (本文是网络的宏观的概念铺垫)目录计算机网络背景网络发展认识"协议"网络协议初识协议分层OSI七层模型TCP/IP五层(或四层)模型报头以太网碰撞路由器IP地址和MAC地址IP地址与MAC地址总结IP地址MAC地址计算机网络背景网络发展        是最开始先有的计算机,计算机后来因为多项技术的水平升高,逐渐的计算机变的小型化、高效化。后来因为计算机其本身的计算能力比较的快速:独立模式:计算机之间相互独立。    如:有三个人,每个人做的不同的事物,但是是需要协作的完成。    而这三个人所做的事是需要进行协作的,然而刚开始因为每一台计算机之间都是互相独立的。所以前面的人处理完了就需要将数据

  8. ruby-on-rails - 具有六边形架构和 DCI 模式的框架和数据库适配器 - 2

    我尝试用Ruby设计一个基于Web的应用程序。我开发了一个简单的核心应用程序,在没有框架和数据库的情况下在六边形架构中实现DCI范例。核心六边形中有小六边形和网络,数据库,日志等适配器。每个六边形都在没有数据库和框架的情况下自行运行。在这种方法中,我如何提供与数据库模型和实体类的关系作为独立于数据库的关系。我想在将来将框架从Rails更改为Sinatra或数据库。事实上,我如何在这个核心Hexagon中实现完全隔离的rails和mongodb的数据库适配器或框架适配器。有什么想法吗? 最佳答案 ROM呢?(Ruby对象映射器)。还有

  9. ruby &&= 边缘案例 - 2

    有点边缘情况,但知道为什么&&=会这样吗?我正在使用1.9.2。obj=Object.newobj.instance_eval{@bar&&=@bar}#=>nil,expectedobj.instance_variables#=>[],soobjhasno@barinstancevariableobj.instance_eval{@bar=@bar&&@bar}#ostensiblythesameas@bar&&=@barobj.instance_variables#=>[:@bar]#whywouldthisversioninitialize@bar?为了比较,||=将实例变量初始

  10. 【Elasticsearch基础】Elasticsearch索引、文档以及映射操作详解 - 2

    文章目录概念索引相关操作创建索引更新副本查看索引删除索引索引的打开与关闭收缩索引索引别名查询索引别名文档相关操作新建文档查询文档更新文档删除文档映射相关操作查询文档映射创建静态映射创建索引并添加映射概念es中有三个概念要清楚,分别为索引、映射和文档(不用死记硬背,大概有个印象就可以)索引可理解为MySQL数据库;映射可理解为MySQL的表结构;文档可理解为MySQL表中的每行数据静态映射和动态映射上面已经介绍了,映射可理解为MySQL的表结构,在MySQL中,向表中插入数据是需要先创建表结构的;但在es中不必这样,可以直接插入文档,es可以根据插入的文档(数据),动态的创建映射(表结构),这就

随机推荐