前几天学了一些Node.js的根底,今日来学习Web运用开发,在开发过程中怎么进行调试,以及怎么线上部署

Web运用开发

HTTP 模块

咱们能够运用 Node.js 内置HTTP模块 树立一个最简略的HTTP服务

const http = require("http");
http
  .createServer((req, res) => {
    res.end("Hello YK!!!");
  })
  .listen(3000, () => {
    console.log("App running at http://127.0.0.1:3000/");
  });

控制台输出

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

网页拜访(也便是发一个GET恳求)

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

Koa

实际开发中都会用到一些结构 比如 Express 和 Koa,今日来介绍下 Koa

介绍

Koa —— 根据Node.js 平台的下一代Web 开发结构

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

安装 npm i koa

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

Koa 它仅仅供给了一个轻量优雅的函数库,使得编写Web 运用变得称心如意, 不在内核办法中绑定任何中间件

const Koa = require("koa");
const app = new Koa();
app.use(async (ctx) => {
  ctx.body = "Hello YK!!!! by Koa";
});
app.listen(3000, () => {
  console.log("App running at http://127.0.0.1:3000/");
});

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

Koa 履行过程

  • 服务启动
    • 实例化application
    • 注册中间件
    • 创立服务、监听端口
  • 承受/处理恳求
    • 获取恳求reqres 目标
    • req -> requestres -> response 封装
    • request & response -> context
    • 履行中间件
    • 输出设置到ctx.body 上的内容

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

Koa的源码相对来说比较友好,能够自己看看源码,只有四个文件

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

中间件

Koa 运用程序是一个包含一组中间件函数的目标,它是依照洋葱模型组织和履行的

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

中间件的履行次序:输出成果1 2 3 2 1

const Koa = require("koa");
const app = new Koa();
app.use(async (ctx, next) => {
  console.log("1 --- 1");
  await next();
  console.log("1 --- 2");
});
app.use(async (ctx, next) => {
  console.log("2 --- 1");
  await next();
  console.log("2 --- 2");
});
app.use(async (ctx, next) => {
  console.log("****3*****");
  ctx.body = "中间件的次序演示";
});
app.listen(3000, () => {
  console.log("App running at http://127.0.0.1:3000/");
});

输出成果1 2 3 2 1

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

咱们简略完结一下中间件

中间件简略代码完结

const fn1 = async (ctx, next) => {
  console.log("before fn1");
  ctx.name = "YKjun";
  await next();
  console.log("after fn1");
};
const fn2 = async (ctx, next) => {
  console.log("before fn2");
  ctx.age = 18;
  await next();
  console.log("after fn2");
};
const fn3 = async (ctx, next) => {
  console.log(ctx);
  console.log("in fn3...");
};
const compose = (middlewares, ctx) => {
  const dispatch = (i) => {
    let fn = middlewares[i];
    return Promise.resolve(
      fn(ctx, () => {
        return dispatch(i + 1);
      })
    );
  };
  return dispatch(0);
};
compose([fn1, fn2, fn3], {});

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

根据中间件原理,获取处理函数履行时间?

const Koa = require("koa");
const app = new Koa();
// logger中间件
app.use(async (ctx, next) => {
  await next();
  const rt = ctx.response.get("X-Response-Time");
  if (ctx.url !== "/favicon.ico") {
    console.log(`${ctx.method} - ${ctx.url} - ${rt}`);
  }
});
// x-response-time 中间件
app.use(async (ctx, next) => {
  const start = Date.now();
  await next();
  const ms = Date.now() - start;
  ctx.set("X-Response-Time", `${ms}ms`);
});
app.use(async (ctx) => {
  let sum = 0;
  for (let i = 0; i < 1e9; i++) {
    sum += i;
  }
  ctx.body = `sum=${sum}`;
});
app.listen(3000, () => {
  console.log("App running at http://127.0.0.1:3000/");
});

能够看出它整个过程是先从上至下然后从下至上

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

常用中间件

  • koa-router路由解析
  • koa-body: request body 解析
  • koa-logger:日志记载
  • koa-views: 模板烘托
  • koa2-cors :跨域处理
  • koa-session:session 处理
  • koa-helmet:安全防护

Koa 中间件繁复,质量参差不齐,需要合理挑选,高效组合…

根据Koa 的前端结构

开源:ThinkJS / Egg …

内部:Turbo、Era、Gulu …

它们做了什么?

  • Koa 目标 response / request / context / application 等扩展
  • Koa 常用中间件库
  • 公司内部服务支撑
  • 进程办理
  • 脚手架
  • ……

调试

断点调试

用node的inspect对指定文件进行断点调试

node --inspect=0.0.0.0:9229 bootstrap.js

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

也能够安装一个ndb

npm install ndb -g
> ndb node bootstrap.js

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

运用 vscode 进行代码调试(我喜爱用这个)

运用之前要先树立一个 json 配置文件

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

打断点进行调试

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

日志调试

  • SDK 上报
  • toutiao.fe.app.2021-07-28.log

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

线上部署

Node.js 保持了JavaScript 在浏览器中单线程的特色(一个进程只开一个线程)

Node.js 虽然是单线程模型,可是其根据事情驱动异步非堵塞模式,能够运用于高并发场景,一起避免了线程创立、线程之间上下文切换所发生的资源开支。

缺点:

  • 无法运用多核CPU
  • 过错会引起整个运用退出,健壮性不足
  • 很多核算占用导致CPU,无法继续执

运用多核CPU

const http = require("http");
http
  .createServer((req, res) => {
    for (let i = 0; i < 1e7; i++) {} // 单核CPU
    res.end(`handled by process.${process.pid}`);
  })
  .listen(8080);

履行一个最简略的HTTP Server

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

这是一个单CPU的服务

怎么运用多核CPU ?

Node.js 供给了cluster / child_process 模块

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

const cluster = require("cluster");
const os = require("os");
if (cluster.isMaster) {
  const cpuLen = os.cpus().length;
  console.log("cpus=", cpuLen);
  for (let i = 0; i < cpuLen; i++) {
    cluster.fork();
  }
} else {
  require("./单核http.js");
}

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

功能比照

ab -c200 -t10 http://localhost:8080/ 测验10秒,并发200

单进程1828

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

多进程6938

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

多进程健壮性

单进程在程序犯错的时候容易整个程序就退出了,咱们来看看多进程的健壮性处理

  • fork:仿制一个作业进程后触发该事情。
  • online:仿制好一个作业进程后,作业进程自动发送一条online音讯给主进程,主进程收到音讯后,触发该事情。
  • listening:作业进程中调用listen()(同享了服务器端Socket)后,发送一条listening音讯给主进程,主进程收到音讯后,触发该事情。
  • disconnect:主进程和作业进程之间IPC通道断开后会触发该事情。
  • exit:有作业进程退出时触发该事情。
  • setup:cluster.setupMaster()履行后触发该事情
const http = require("http");
const numCPUs = require("os").cpus().length;
const cluster = require("cluster");
if (cluster.isMaster) {
  console.log("Master process id is", process.pid);
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }
  cluster.on("exit", function (worker, code, signal) {
    console.log("worker process died, id", worker.process.pid);
    cluster.fork(); // 退出之后立刻fork一个新进程
  });
} else {
  const server = http.createServer();
  server.on("request", (req, res) => {
    res.writeHead(200);
    console.log(process.pid);
    res.end("hello world\n");
  });
  server.listen(8080);
}

进程看护

咱们不一定每次都要手写办理各种进程,咱们能够运用办理工具来完结进程看护。

Node.js 进程办理工具:

  • 多进程
  • 自动重启
  • 负载均衡
  • 日志检查
  • 功能监控

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署
【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

运用 pm2 进程办理与监控

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

杂乱核算

Node.js 杂乱核算,占用CPU 卡住了怎么办?

const http = require("http");
const complexCalc = () => {
  console.time("核算耗时");
  let sum = 0;
  for (let i = 0; i < 1e10; i++) {
    sum += i;
  }
  console.timeEnd("核算耗时");
  return sum;
};
const server = http.createServer();
server.on("request", (req, res) => {
  if (req.url === "/compute") {
    const sum = complexCalc();
    res.end(`sum is ${sum} \n`);
  } else {
    res.end("success");
  }
});
server.listen(8000);

比如咱们这里就来一个循环核算模仿杂乱核算

核算耗时十几秒

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

如果咱们这时候在恳求其他比如127.0.0.1:8000/ping 此时也不能当即输出成果,而是会发生堵塞,要等杂乱核算完结才会输出success

杂乱核算会占用CPU核算很长时间,简略的使命也会等候杂乱的使命核算完才能被履行

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

能够考虑运用多进程,将杂乱核算,放入子进程来处理,不占用主进程,等杂乱核算完结,把成果发送父进程,然后就能够得到成果

多进程与进程通信

杂乱核算子进程

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

主进程

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署

前端开发与后端开发比照

最终咱们来比照比照前端和后端开发的关注点吧~

前端开发

  • 跟浏览器打交道,兼容性问题
  • UI 规范与组件化
  • 加载速度、履行功能、烘托功能
  • Crash 监控、白屏监控
  • XSS、CSRF 等安全漏洞

服务端开发

  • 数据库、Redis 等存储服务
  • 服务器办理、容灾
  • 功能、内存走漏
  • 服务监控、过错监控、流量监控、报警
  • SQL 注入、目录遍历等安全漏洞

【青训营】Node.js基础 - Web应用开发 - 开发调试 - 线上部署