青训营node.js基础-web应用开发-开发调试-线上部署(代码片段)

YK菌 YK菌     2023-01-10     381

关键词:

前几天学了一些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/");
  );

控制台输出

网页访问(也就是发一个GET请求)

Koa

实际开发中都会用到一些框架 比如 Express 和 Koa,今天来介绍下 Koa

介绍

Koa —— 基于Node.js 平台的下一代Web 开发框架

安装 npm i koa

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/");
);

Koa 执行过程

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

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

中间件

Koa 应用程序是一个包含一组中间件函数的对象,它是按照洋葱模型组织和执行的

中间件的执行顺序:输出结果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

我们简单实现一下中间件

中间件简单代码实现

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], );

基于中间件原理,获取处理函数执行时间?

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", `$msms`);
);

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/");
);

可以看出它整个过程是先从上至下然后从下至上

常用中间件

  • 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

也可以安装一个ndb

npm install ndb -g
> ndb node bootstrap.js

使用 vscode 进行代码调试(我喜欢用这个)

使用之前要先建立一个 json 配置文件

打断点进行调试

日志调试

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

线上部署

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

这是一个单CPU的服务

如何利用多核CPU ?

Node.js 提供了cluster / child_process 模块

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");

性能对比

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

单进程1828

多进程6938

多进程健壮性

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

  • 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 进程管理工具:

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

使用 pm2 进程管理与监控

复杂计算

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);

比如我们这里就来一个循环计算模拟复杂计算

计算耗时十几秒

如果我们这时候在请求别的比如127.0.0.1:8000/ping 此时也不能立即输出结果,而是会产生阻塞,要等复杂计算完成才会输出success

复杂计算会占用CPU计算很长时间,简单的任务也会等待复杂的任务计算完才能被执行

可以考虑使用多进程,将复杂计算,放入子进程来处理,不占用主进程,等复杂计算完成,把结果发送父进程,然后就可以得到结果

多进程与进程通信

复杂计算子进程

主进程

前端开发与后端开发对比

最后我们来对比对比前端和后端开发的关注点吧~

前端开发

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

服务端开发

  • 数据库、Redis 等存储服务
  • 服务器管理、容灾
  • 性能、内存泄露
  • 服务监控、错误监控、流量监控、报警
  • SQL 注入、目录遍历等安全漏洞

青训营node.js基础-异步编程四种解决方案(代码片段)

文章目录异步编程概述异步编程解决方案CallbackPromiseCallback转为PromiseawaitEvent参考有异步I/O,必有异步编程!今天来学习Node.js里的异步编程!异步编程概述曾经的单线程模型在同步I/O的影响下,由于I/O调用缓慢ÿ... 查看详情

青训营node.js基础-特点-模块化commonjs&esm-npm包管理(代码片段)

文章目录起步安装与运行版本管理特点异步I/O单线程多进程的浏览器跨平台应用场景模块化机制CommonJS规范机制加载方式npm包查找原则npm缓存其他模块化规范ESModules(ESM)CommonJSVSESMCommonJS:值的**拷贝**ESM:值的**引用**常用... 查看详情

青训营node.js基础-特点-模块化commonjs&esm-npm包管理(代码片段)

文章目录起步安装与运行版本管理特点异步I/O单线程多进程的浏览器跨平台应用场景模块化机制CommonJS规范机制加载方式npm包查找原则npm缓存其他模块化规范ESModules(ESM)CommonJSVSESMCommonJS:值的**拷贝**ESM:值的**引用**常用... 查看详情

青训营html基础-语义化标签-浏览器渲染过程-笔记及拓展(代码片段)

...)博主还是很久之前学习的,这次趁着字节跳动青训营的活动,就再学习一遍HTML。一小时的课程,巩固了之前的一些知识,也学到了很多新知识。我把这次课程的内容与我这一年来学习前端的经验相结合,... 查看详情

go语言上手|青训营笔记(代码片段)

这是我参与「第三届青训营-后端场」笔记创作活动的的第一篇笔记。文章目录语法速览基础语法第一:类型第二:内置库部分json库的使用时间库的使用字符串和数字互转os相关信息实战项目猜谜游戏(pass,过于... 查看详情

字节跳动青训营--前端day8(代码片段)

...SSG1.CSR客户端渲染(Client-SideRendering)。常见B端WEB应用开发模式,前后端分离,服务器压力相对更轻,渲染工作在客户端进行,服务器直接返回不加工的HTML用户在后去访问操作(不会嵌套后端代码,... 查看详情

结营啦!有缘相聚于青训,未来高处见呀~~(代码片段)

📸叮!记·字节跳动第一届青训营顺利结营啦!从8月份的青训营,到9月份的实训营,搁置了许久的结营心得终于拾起来辽!🎬开营进行时从答疑会开始,负责人仔细的阐述了本次训练营的性质和... 查看详情

字节跳动青训营笔试题解(代码片段)

...圈题目思路代码四、简答题题目思路前言第五届字节跳动青训营-后端专场笔试题解,简单做了一下,选择题和简答题不知道是否正确,编程题是通过了的,有问题欢迎评论,我会及时改正的~一、单选题选AQUIC&... 查看详情

字节跳动青训营笔试题解(代码片段)

...圈题目思路代码四、简答题题目思路前言第五届字节跳动青训营-后端专场笔试题解,简单做了一下,选择题和简答题不知道是否正确,编程题是通过了的,有问题欢迎评论,我会及时改正的~一、单选题选AQUIC&... 查看详情

青训营pro️从0到1实现一个自己的前端约定路由项目脚手架️工具~(代码片段)

文章目录前言一、Node基础API核心API-无需`require`内置API-需要`require`无需`install`1.fs与异步IO①同步读取文件②异步读取文件③promisify2.buffer与字符集3.http练习1node基础fs\\buffer\\http搭建一个http服务4.stream5.子进程二... 查看详情

青训营pro️从0到1实现一个自己的前端约定路由项目脚手架️工具~(代码片段)

文章目录前言一、Node基础API核心API-无需`require`内置API-需要`require`无需`install`1.fs与异步IO①同步读取文件②异步读取文件③promisify2.buffer与字符集3.http练习1node基础fs\\buffer\\http搭建一个http服务4.stream5.子进程二... 查看详情

字节跳动青训营每日一练编程题

1:实现一个36进制的加法0-9a-z。#include<bits/stdc++.h>typedeflonglongll;constllN=2e5+10;usingnamespacestd;ints[N];intmain()int_;stringa,b;while(cin>>a>>b)stringans;intpos 查看详情

青训营月影老师告诉我写好javascript的四大技巧——保证正确(代码片段)

文章目录起步洗牌算法验证正确性解决方案一:多洗几次解决方案二:随机采样应用抽奖分红包总结更多相关博文如何写好JavaScript是每一个前端工程师一直以来在思考的问题,月影老师告诉我们一些写好JavaScript的原... 查看详情

青训营月影老师告诉我写好javascript的三大原则之——过程抽象(代码片段)

...5.总结过程抽象/HOF/装饰器命令式/声明式参加了这次字节青训营的活动,见到了传说中的月影老师࿰ 查看详情

在chrome开发者工具中调试node.js

命令行工具devtool,它可以在Chrome的开发者工具中运行Node.js程序。下面的记录显示了在一个HTTP服务器中设置断点的情况。该工具基于Electron将Node.js和Chromium的功能融合在了一起。它的目的在于为调试、分析和开发Node.js应用程序提... 查看详情

在visualstudio上开发node.js程序——远程调试及发布到azure

【题外话】上次介绍了VS上开发Node.js的插件Node.jsToolsforVisualStudio(NTVS),其提供了非常方便的开发和调试功能,当然很多情况下由于平台限制等原因需要在其他机器上运行程序,进而需要远程调试功能,不过还好,NTVS提供的远... 查看详情

node.js入门01:基础使用与说明(代码片段)

文章目录前言下载与安装入门使用运行JavaScript代码简单的web服务器示例内置功能调试代码异步操作与事件循环为什么需要异步操作实现自己的异步操作事件循环总结前言传统的来说JavaScript是运行在浏览器中的网页上的脚本语言&... 查看详情

vscode调试node.js

在开发的过程中,几乎不可能一次性就能写出毫无破绽的程序,断点调试代码是一个普遍的需求。作为前端开发工程师,以往我们开发的JavaScript程序都运行在浏览器端,利用Chrome提供的开发者工具就可以方便的进行源码断点调... 查看详情