首页 文章 精选 留言 我的

精选列表

搜索[nodejs],共1637篇文章
优秀的个人博客,低调大师

阿里云物联网平台AMQP服务端订阅NodeJS Demo

Step By Step 配置服务端订阅 1、创建消费组 2、创建订阅 参数获取 3、ConsumerGroupId获取位置 4、AccessKeyId、AccessKeySecret及Uid获取 参考地址:阿里云常见参数获取位置 5、iotInstanceId 独享实例需要指定,公共实例配置为空即可。 6、ClientId可以任意指定,例如设置为:tarodemo。 7、Host: ${uid}.iot-amqp.${regionId}.aliyuncs.com 例如:184*.iot-amqp.cn-shanghai.aliyuncs.com SDK 安装 npm install rhea Code Sample const container = require('rhea'); const crypto = require('crypto'); //建立连接。 var connection = container.connect({ //接入域名,请参见AMQP客户端接入说明文档。 'host': '18482************.iot-amqp.cn-shanghai.aliyuncs.com', 'port': 5671, 'transport':'tls', 'reconnect':true, 'idle_time_out':60000, //userName组装方法,请参见AMQP客户端接入说明文档。其中的iotInstanceId,购买的实例请填写实例ID,公共实例请填空字符串""。 //'username':'${YourClientId}|authMode=aksign,signMethod=hmacsha1,timestamp=1573489088171,authId=${YourAccessKeyId},iotInstanceId=${YourIotInstanceId},consumerGroupId=${YourConsumerGroupId}|', 'username':'tarodemo|authMode=aksign,signMethod=hmacsha1,timestamp=1573489088171,authId=LTAIOZZgYXPsMbDA,iotInstanceId=,consumerGroupId=R45CIUGUE3LJie1uaFjI000100|', //计算签名,password组装方法,请参见AMQP客户端接入说明文档。 //'password': hmacSha1('${YourAccessKeySecret}', 'authId=${YourAccessKeyId}&timestamp=1573489088171'), 'password': hmacSha1('v7C***********', 'authId=**********&timestamp=1573489088171'), }); //创建Receiver-Link。 var receiver = connection.open_receiver(); //接收云端推送消息的回调函数。 container.on('message', function (context) { var msg = context.message; var messageId = msg.message_id; var topic = msg.application_properties.topic; var content = Buffer.from(msg.body.content).toString(); // 输出内容 console.log(content); //发送ack,注意不要在回调函数有耗时逻辑。 context.delivery.accept(); }); //计算password签名。 function hmacSha1(key, context) { return Buffer.from(crypto.createHmac('sha1', key).update(context).digest()) .toString('base64'); } 测试效果 参考链接 Node.js SDK接入示例阿里云常见参数获取位置

优秀的个人博客,低调大师

nodejs 搭建 RESTful API 服务器的常用包及其简介

常用包 框架: yarn add express 数据库链接: yarn add sequelize yarn add mysql2 处理 favicon: yarn add serve-favicon 纪录日志: yarn add morgan 生成文档: yarn add --dev apidoc 解析请求参数: yarn add body-parser 设置 HTTP 头(提高安全性): yarn add helmet 文件变动监控(自动重启): yarn add --dev nodemon (启动服务器脚本中替换 node 即可) 允许 cors 请求: yarn add cors 压缩数据: yarn add compression 响应时间: yarn add response-time 数据伪造: yarn add faker – 数据验证: yarn add express-validator 进程管理: yarn add --dev pm2 带重启(nodemon用于开发环境),日志,负载均衡 serve-favicon 优点:把请求 favicon 的记录从日志中去除。缓存 icon 提高性能。使用兼容性最好的 Content-Type。 使用方式: var favicon = require('serve-favicon') app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))) morgan 使用方式: var morgan = require('morgan') app.use(morgan('combined')) //参数可选 dev tiny 或自定义输出日志格式,详见文档 // 导出日志文件 var express = require('express') var fs = require('fs') var morgan = require('morgan') var path = require('path') var app = express() // create a write stream (in append mode) var accessLogStream = fs.createWriteStream(path.join(__dirname, 'access.log'), {flags: 'a'}) // setup the logger app.use(morgan('combined', {stream: accessLogStream})) body-parser 使用方式: var bodyParser = require('body-parser') // parse application/x-www-form-urlencoded app.use(bodyParser.urlencoded({ extended: false })) //设置 false 使用 querystring 解析,处理 ajax 提交的复杂数据更在行。(true 使用 qs 解析) // parse application/json app.use(bodyParser.json()) apidoc 使用方式: 生成文档命令: apidoc -i routes/ -o doc/( routes 是程序入口,doc 是文档出口) 注释示例: /** * @api {get} /user/:id Read data of a User * @apiVersion 0.3.0 * @apiName GetUser * @apiGroup User * @apiPermission admin * * @apiDescription Compare Verison 0.3.0 with 0.2.0 and you will see the green markers with new items in version 0.3.0 and red markers with removed items since 0.2.0. * * @apiParam {String} id The Users-ID. * * @apiSuccess {String} id The Users-ID. * @apiSuccess {Date} registered Registration Date. * @apiSuccess {Date} name Fullname of the User. * @apiSuccess {String[]} nicknames List of Users nicknames (Array of Strings). * @apiSuccess {Object} profile Profile data (example for an Object) * @apiSuccess {Number} profile.age Users age. * @apiSuccess {String} profile.image Avatar-Image. * @apiSuccess {Object[]} options List of Users options (Array of Objects). * @apiSuccess {String} options.name Option Name. * @apiSuccess {String} options.value Option Value. * * @apiError NoAccessRight Only authenticated Admins can access the data. * @apiError UserNotFound The <code>id</code> of the User was not found. * * @apiErrorExample Response (example): * HTTP/1.1 401 Not Authenticated * { * "error": "NoAccessRight" * } */ helmet var express = require('express') var helmet = require('helmet') var app = express() app.use(helmet()) cors 使用方式: // 允许所有跨域请求 var express = require('express') var cors = require('cors') var app = express() app.use(cors()) // 允许某路由的跨域请求 app.get('/products/:id', cors(), function (req, res, next) { res.json({msg: 'This is CORS-enabled for a Single Route'}) }) // 允许某些域的请求 var whitelist = ['http://example1.com', 'http://example2.com'] var corsOptions = { origin: function (origin, callback) { if (whitelist.indexOf(origin) !== -1) { callback(null, true) } else { callback(new Error('Not allowed by CORS')) } } } app.get('/products/:id', cors(corsOptions), function (req, res, next) { res.json({msg: 'This is CORS-enabled for a whitelisted domain.'}) }) // 允许 GET/POST 以外的请求 app.options('/products/:id', cors()) // enable pre-flight request for DELETE request app.del('/products/:id', cors(), function (req, res, next) { res.json({msg: 'This is CORS-enabled for all origins!'}) }) // 对所有路由允许 app.options('*', cors()) // include before other routes compression 使用方式: var compression = require('compression') var express = require('express') var app = express() app.use(compression({filter: shouldCompress})) function shouldCompress (req, res) { if (req.headers['x-no-compression']) { // don't compress responses with this request header return false } // fallback to standard filter function return compression.filter(req, res) } response-time 使用方式: 该中间件将响应时间写在响应头 X-Response-Time 中 var express = require('express') var responseTime = require('response-time') var app = express() // 统计响应进入该中间件到写完响应头的毫秒数 app.use(responseTime()) express-validator 验证规则 // 初始化 app.use(expressValidator()) // this line must be immediately after any of the bodyParser middlewares! // 检查参数是否符合标准 req.check('testparam', 'Error Message').notEmpty().isInt() // 将参数转化为 req.sanitize('postparam').toBoolean() // 返回验证结果 req.getValidationResult().then(function(result) { // do something with the validation result }) pm2 pm2 start app.js --name="api" # Start application and name it "api" pm2 stop all # Stop all apps pm2 logs # Display logs of all apps pm2 web 后访问 http://localhost:9615/ # 查看系统状态

优秀的个人博客,低调大师

前端技术探秘-Nodejs的CommonJS规范实现原理 | 京东物流技术团队

了解Node.js Node.js是一个基于ChromeV8引擎的JavaScript运行环境,使用了一个事件驱动、非阻塞式I/O模型,让JavaScript 运行在服务端的开发平台,它让JavaScript成为与PHP、Python、Perl、Ruby等服务端语言平起平坐的脚本语言。Node中增添了很多内置的模块,提供各种各样的功能,同时也提供许多第三方模块。 模块的问题 为什么要有模块 复杂的前端项目需要做分层处理,按照功能、业务、组件拆分成模块, 模块化的项目至少有以下优点: 便于单元测试 便于同事间协作 抽离公共方法, 开发快捷 按需加载, 性能优秀 高内聚低耦合 防止变量冲突 方便代码项目维护 几种模块化规范 CMD(SeaJS 实现了 CMD) AMD(RequireJS 实现了 AMD) UMD(同时支持 AMD 和 CMD) IIFE (自执行函数) CommonJS (Node 采用了 CommonJS) ES Module 规范 (JS 官方的模块化方案) Node中的模块 Node中采用了 CommonJS 规范 实现原理: Node中会读取文件,拿到内容实现模块化, Require方法 同步引用 tips:Node中任何js文件都是一个模块,每一个文件都是模块 Node中模块类型 内置模块,属于核心模块,无需安装,在项目中不需要相对路径引用, Node自身提供。 文件模块,程序员自己书写的js文件模块。 第三方模块, 需要安装, 安装之后不用加路径。 Node中内置模块 fs filesystem 操作文件都需要用到这个模块 const path = require('path'); // 处理路径 const fs = require('fs'); // file system // // 同步读取 let content = fs.readFileSync(path.resolve(__dirname, 'test.js'), 'utf8'); console.log(content); let exists = fs.existsSync(path.resolve(__dirname, 'test1.js')); console.log(exists); path 路径处理 const path = require('path'); // 处理路径 // join / resolve 用的时候可以混用 console.log(path.join('a', 'b', 'c', '..', '/')) // 根据已经有的路径来解析绝对路径, 可以用他来解析配置文件 console.log(path.resolve('a', 'b', '/')); // resolve 不支持/ 会解析成根路径 console.log(path.join(__dirname, 'a')) console.log(path.extname('1.js')) console.log(path.dirname(__dirname)); // 解析父目录 vm 运行代码 字符串如何能变成 JS 执行呢? 1.eval eval中的代码执行时的作用域为当前作用域。它可以访问到函数中的局部变量。 let test = 'global scope' global.test1 = '123' function b(){ test = 'fn scope' eval('console.log(test)'); //local scope new Function('console.log(test1)')() // 123 new Function('console.log(test)')() //global scope } b() 2.new Function new Function()创建函数时,不是引用当前的词法环境,而是引用全局环境,Function中的表达式使用的变量要么是传入的参数要么是全局的值 Function可以获取全局变量,所以它还是可能会有变量污染的情况出现 function getFn() { let value = "test" let fn = new Function('console.log(value)') return fn } getFn()() global.a = 100 // 挂在到全局对象global上 new Function("console.log(a)")() // 100 3.vm 前面两种方式,我们一直强调一个概念,那就是变量的污染 VM的特点就是不受环境的影响,也可以说他就是一个沙箱环境 在Node中全局变量是在多个模块下共享的,所以尽量不要在global中定义属性 所以,vm.runInThisContext可以访问到global上的全局变量,但是访问不到自定义的变量。而vm.runInNewContext访问不到global,也访问不到自定义变量,他存在于一个全新的执行上下文 const vm = require('vm') global.a = 1 // vm.runInThisContext("console.log(a)") vm.runInThisContext("a = 100") // 沙箱,独立的环境 console.log(a) // 1 vm.runInNewContext('console.log(a)') console.log(a) // a is not defined Node模块化的实现 node中是自带模块化机制的,每个文件就是一个单独的模块,并且它遵循的是CommonJS规范,也就是使用require的方式导入模块,通过module.export的方式导出模块。 node模块的运行机制也很简单,其实就是在每一个模块外层包裹了一层函数,有了函数的包裹就可以实现代码间的作用域隔离。 我们先在一个js文件中直接打印arguments,得到的结果如下图所示,我们先记住这些参数。 console.log(arguments) // exports, require, module, __filename, __dirname Node中通过modules.export 导出,require 引入。其中require依赖node中的fs模块来加载模块文件,通过fs.readFile读取到的是一个字符串。 在javascrpt中可以通过eval或者new Function的方式来将一个字符串转换成js代码来运行。但是前面提到过,他们都有一个致命的问题,就是变量的污染。 实现require模块加载器 首先导入依赖的模块path,fs,vm, 并且创建一个Require函数,这个函数接收一个modulePath参数,表示要导入的文件路径 const path = require('path'); const fs = require('fs'); const vm = require('vm'); // 定义导入类,参数为模块路径 function Require(modulePath) { ... } 在Require中获取到模块的绝对路径,使用fs加载模块,这里读取模块内容使用new Module来抽象,使用tryModuleLoad来加载模块内容,Module和tryModuleLoad稍后实现,Require的返回值应该是模块的内容,也就是module.exports。 // 定义导入类,参数为模块路径 function Require(modulePath) { // 获取当前要加载的绝对路径 let absPathname = path.resolve(__dirname, modulePath); // 创建模块,新建Module实例 const module = new Module(absPathname); // 加载当前模块 tryModuleLoad(module); // 返回exports对象 return module.exports; } Module的实现就是给模块创建一个exports对象,tryModuleLoad执行的时候将内容加入到exports中,id就是模块的绝对路径。 // 定义模块, 添加文件id标识和exports属性 function Module(id) { this.id = id; // 读取到的文件内容会放在exports中 this.exports = {}; } node模块是运行在一个函数中,这里给Module挂载静态属性wrapper,里面定义一下这个函数的字符串,wrapper是一个数组,数组的第一个元素就是函数的参数部分,其中有exports,module,Require,__dirname,__filename, 都是模块中常用的全局变量. 第二个参数就是函数的结束部分。两部分都是字符串,使用的时候将他们包裹在模块的字符串外部就可以了。 // 定义包裹模块内容的函数 Module.wrapper = [ "(function(exports, module, Require, __dirname, __filename) {", "})" ] _extensions用于针对不同的模块扩展名使用不同的加载方式,比如JSON和javascript加载方式肯定是不同的。JSON使用JSON.parse来运行。 javascript使用vm.runInThisContext来运行,可以看到fs.readFileSync传入的是module.id也就是Module定义时候id存储的是模块的绝对路径,读取到的content是一个字符串,使用Module.wrapper来包裹一下就相当于在这个模块外部又包裹了一个函数,也就实现了私有作用域。 使用call来执行fn函数,第一个参数改变运行的this传入module.exports,后面的参数就是函数外面包裹参数exports, module, Require, __dirname, __filename。/ // 定义扩展名,不同的扩展名,加载方式不同,实现js和json Module._extensions = { '.js'(module) { const content = fs.readFileSync(module.id, 'utf8'); const fnStr = Module.wrapper[0] + content + Module.wrapper[1]; const fn = vm.runInThisContext(fnStr); fn.call(module.exports, module.exports, module, Require,__filename,__dirname); }, '.json'(module) { const json = fs.readFileSync(module.id, 'utf8'); module.exports = JSON.parse(json); // 把文件的结果放在exports属性上 } } tryModuleLoad函数接收的是模块对象,通过path.extname来获取模块的后缀名,然后使用Module._extensions来加载模块。 // 定义模块加载方法 function tryModuleLoad(module) { // 获取扩展名 const extension = path.extname(module.id); // 通过后缀加载当前模块 Module._extensions[extension](module); // 策略模式??? } 到此Require加载机制基本就写完了。Require加载模块的时候传入模块名称,在Require方法中使用path.resolve(__dirname, modulePath)获取到文件的绝对路径。然后通过new Module实例化的方式创建module对象,将模块的绝对路径存储在module的id属性中,在module中创建exports属性为一个json对象。 使用tryModuleLoad方法去加载模块,tryModuleLoad中使用path.extname获取到文件的扩展名,然后根据扩展名来执行对应的模块加载机制。 最终将加载到的模块挂载module.exports中。tryModuleLoad执行完毕之后module.exports已经存在了,直接返回就可以了。 接下来,我们给模块添加缓存。就是文件加载的时候将文件放入缓存中,再去加载模块时先看缓存中是否存在,如果存在直接使用,如果不存在再去重新加载,加载之后再放入缓存。 // 定义导入类,参数为模块路径 function Require(modulePath) { // 获取当前要加载的绝对路径 let absPathname = path.resolve(__dirname, modulePath); // 从缓存中读取,如果存在,直接返回结果 if (Module._cache[absPathname]) { return Module._cache[absPathname].exports; } // 创建模块,新建Module实例 const module = new Module(absPathname); // 添加缓存 Module._cache[absPathname] = module; // 加载当前模块 tryModuleLoad(module); // 返回exports对象 return module.exports; } 增加功能:省略模块后缀名。 自动给模块添加后缀名,实现省略后缀名加载模块,其实也就是如果文件没有后缀名的时候遍历一下所有的后缀名看一下文件是否存在。 // 定义导入类,参数为模块路径 function Require(modulePath) { // 获取当前要加载的绝对路径 let absPathname = path.resolve(__dirname, modulePath); // 获取所有后缀名 const extNames = Object.keys(Module._extensions); let index = 0; // 存储原始文件路径 const oldPath = absPathname; function findExt(absPathname) { if (index === extNames.length) { return throw new Error('文件不存在'); } try { fs.accessSync(absPathname); return absPathname; } catch(e) { const ext = extNames[index++]; findExt(oldPath + ext); } } // 递归追加后缀名,判断文件是否存在 absPathname = findExt(absPathname); // 从缓存中读取,如果存在,直接返回结果 if (Module._cache[absPathname]) { return Module._cache[absPathname].exports; } // 创建模块,新建Module实例 const module = new Module(absPathname); // 添加缓存 Module._cache[absPathname] = module; // 加载当前模块 tryModuleLoad(module); // 返回exports对象 return module.exports; } 源代码调试 我们可以通过VSCode 调试Node.js 步骤 创建文件a.js module.exports = 'abc' 1.文件test.js let r = require('./a') console.log(r) 1.配置debug,本质是配置.vscode/launch.json文件,而这个文件的本质是能提供多个启动命令入口选择。 一些常见参数如下: program控制启动文件的路径(即入口文件) name下拉菜单中显示的名称(该命令对应的入口名称) request分为 launch(启动)和 attach(附加)(进程已经启动) skipFiles指定单步调试跳过的代码 runtimeExecutable设置运行时可执行文件,默认是 node,可以设置成 nodemon,ts-node,npm 等 修改launch.json,skipFiles指定单步调试跳过的代码 将test.js 文件中的require方法所在行前面打断点 执行调试,进入源码相关入口方法 梳理代码步骤 1.首先进入到进入到require方法:Module.prototype.require 2.调试到Module._load 方法中,该方法返回module.exports,Module._resolveFilename方法返回处理之后的文件地址,将文件改为绝对地址,同时如果文件没有后缀就加上文件后缀。 3.这里定义了Module类。id为文件名。此类中定义了exports属性 4.接着调试到module.load 方法,该方法中使用了策略模式,Module._extensions[extension](this, filename)根据传入的文件后缀名不同调用不同的方法 5.进入到该方法中,看到了核心代码,读取传入的文件地址参数,拿到该文件中的字符串内容,执行module._compile 6.此方法中执行wrapSafe方法。将字符串前后添加函数前后缀,并用Node中的vm模块中的runInthisContext方法执行字符串,便直接执行到了传入文件中的console.log代码行内容。 至此,整个Node中实现require方法的整个流程代码已经调试完毕,通过对源代码的调试,可以帮助我们学习其实现思路,代码风格及规范,有助于帮助我们实现工具库,提升我们的代码思路,同时我们知道相关原理,也对我们解决日常开发工作中遇到的问题提供帮助。 作者:京东物流 乔盼盼 来源:京东云开发者社区 自猿其说Tech 转载请注明来源

优秀的个人博客,低调大师

又一阵后浪:横空出世的Deno会取代NodeJS吗?

云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! Deno 1.0.0版本于近期发布了,它是由Ryan Dahl发明的,他还因发明Node.js这个“小玩意儿”而闻名。 Node.js听起来很熟悉吧?这是否意味着Deno实际上已经自动取代了Node而我们该开始计划重构冲刺呢? 现在下结论显然为时尚早,但以下几个事实可能在很大程度上决定了Deno的发布。 从头说起 2018年,Ryan在一次演讲中谈到了他认为Node存在的10大问题。演讲的最后,他展示了他当时正在构建的、还只是一个小系统的Deno,也就是大家口中的Node.js 2.0版本,他对原有版本做了改进,也更加安全。 两年后,Deno 1.0正式发布。其后端有一个全新的JavaScript运行环境,但它是用Rust编写的,而不是用C++。它以Tokio平台为基础(该平台为JavaScript提供其所需要的异步运行环境),仍可运行Google V8引擎。 还有什么新鲜的吗? 我们不仅仅是在讨论一个和现有的Node.js完全兼容的新的JavaScript运行环境,Ryan还利用了这个机会,在Deno中加入了一些他认为在早期创作中缺失的东西。 安全集成 默认设置中,Node.js允许用户访问所有内容,这意味着你可以读写文件系统、发出请求、访问环境变量等等。尽管作为开发人员,拥有这种访问权限是有利的,但如果在编写自己的代码时不够小心,也会带来安全风险。 因此,Deno使用命令行参数来启用或禁用对不同安全特性的访问。如果你需要让你的脚本访问/etc 文件夹,可以输入: deno --allow-read=/etcmyscript.ts 你的代码将从文件夹中读取,你会得到一个安全异常提示。这类似于其他平台处理安全性的方式。 如果你是Android用户,你一定已经收到了很多应用程序的要求,允许它们访问你手机中的不同系统(如联系人、电话、文件夹等)。这里也一样。通过在执行脚本的命令行中使用这些标志,可以提供代码所需的权限。 一个更完整的标准库 自Node的第一个版本开始,JavaScript就已经改进了它的标准库,但是与其他语言相比,它还有很多不足。 Deno也试图改进这一点,据说它会拥有一个非常完整的标准库,能让开发人员使用官方工具来执行基本任务,且只需使用外部库(alaNPM)来完成复杂的任务。 从本质上讲,Deno开箱即用,它的自带工具可以为终端文本添加颜色、处理外部数据结构(如二进制、csv、yaml和其他数据结构)、生成UUID,甚至编写websockets。还有其他可用的更基本模块,比如文件系统访问、日期帮助器函数、与http相关的函数等等。 集成版TypeScript 如果你是TypeScript的忠实用户,那么不需要外部工具,Deno就会帮你搞定很多工作,默认情况下JavaScript的转换在内部即可完成,这一点无需担心。 尽管默认情况下Deno会做很多工作,但你可以使用自己的tsconfig.json文件覆盖配置: deno run -c tsconfig.json[your-script.ts] 默认模式是使用严格模式,因此,进行任何欠考虑的编码操作都会立即收到警告。 不再需要NPM和node_modules文件夹 这是个大问题。会不会太臃肿了?这种分散依赖关系的方式是错误的吗?这自然是Node最具争议的一大方面,Deno决定完全摆脱它。 那Deno是如何处理依赖项的呢?目前的方法是,允许你从任何地方索取模块。换言之,你可以这样做: import * as log from"https://deno.land/std/log/mod.ts"; 你无需拥有自己的集中存储库,但必须谨慎操作,因为从无法控制的第三方源导入模块会让你处于开放暴露的状态。 事实上,我们的好朋友package.json也不见了。现在通过在名为deps.ts的文件中列出一系列模块及其各自的URL,来简化依赖性管理。你肯定会问,版本控制呢?你可以在URL上指定包版本。虽然不是很方便,但行得通。 一个正常的deps.ts文件是这样的: export { assert } from"https://deno.land/std@v0.39.0/testing/asserts.ts"; export { green, bold } from"https://deno.land/std@v0.39.0/fmt/colors.ts"; 这将重新导出模块。如果你想更改模块的版本,需对URL进行相应的简化修改。在第一次执行脚本时,导入的代码会被缓存,直到再次使用--reload 标志运行为止。 还有别的吗? Deno还有其他特点,比如它拥有了更多的“开箱即用”工具,包括测试运行器、调试器、文件监视程序等。但话说回来,其中一些只是由语言提供的API接口,你需要编写出自己的工具才能使用它们。 以 Deno.watchFs提供的文件监视器API接口为例,如果你正在寻找与nodemon类似的解决方案,那你必须自己完成。下面是解决类似问题的23行脚本: Deno会很快取代Node.js吗? 老实说,不一定。有些人自Node.js 0.10版本推出就开始使用Node js,甚至将其应用于生产。我们过去之所以这样做是因为没有与其类似的系统。 PHP、Python甚至Ruby都无法在后端与JavaScript和异步I/O模型相提并论,更不用说Java和. NET了。这些年来,Node和JavaScript不断改进升级,以满足业界需求。 它是完美的吗?当然不是。和生活中的其他事情一样,在编程语言方面也很难做到十全十美。 Deno也不例外。目前它还只是一个计划用2年时间达成目标的想法。它还没有在生产系统中试验和测试过,没有被审查过,也没有应用于奇怪的、意想不到的使用情况,我们无法了解它是如何处理这些极端情况的。 也许在一年后,我们会听到公司分享他们有关应用Deno的经验、他们如何解决新发现的缺陷,最终,它背后的群体将使用Deno,让它“物尽其用”。而在此之前,Deno还只是早期使用者的玩具。 它会取代Node吗?谁知道呢,一起拭目以待吧! 【云栖号在线课堂】每天都有产品技术专家分享!课程地址:https://yqh.aliyun.com/live 立即加入社群,与专家面对面,及时了解课程最新动态!【云栖号在线课堂 社群】https://c.tb.cn/F3.Z8gvnK 原文发布时间:2020-06-01本文作者:读芯术本文来自:“读芯术公众号”,了解相关信息可以关注“读芯术”

优秀的个人博客,低调大师

pm2管理多个nodejs项目nginx反向代理多域名https协议ssl证书

首先下载免费证书,上传至服务器,证书有很多种,以上阿里云免费版证书分为DV、OV、EV三种: DV SSL证书:亦是域名验证型证书,申请该证书时,CA(证书颁发机构)只需审核域名的所有权即可,整个流程非常简单,无需人工,由系统自动完成。所以时间上是比较快的,一般10分钟左右就能签发,而且价格比较便宜,相对来说等级也是比较低的,适合个人网站及小型组织或企业网站。 OV SSL证书:这个是企业验证型,比DV证书的验证要求要高一些。它不仅需要验证域名的所有权,还需要验证企业身份,验证是需提供企业信息和公司营业执照扫描件等资料,都是通过人工审核的,一般需要3-5个工作日才能颁发,价格也相对较高一些,但是安全等级大大的提高了,适合一般组织或中小型企业网站。 EV SSL证书:这是目前业界最高安全级别的证书,功能比前两位都强大。如果用户安装了此证书,浏览器不仅会显示绿色的地址栏及https前缀和安全锁的标志,而且还会显示企业名,这个不仅看上去就很高大上,而且真的更安全。当然了,EV SSL证书审核也是最严格的,需要提供企业信息和公司营业执照扫描件等资料以及邓白氏或者律师意见信,CA机构会人工验证组织和电话信息,一般3-7个工作日才能颁发,价格也是相对比较高的,适用于在线交易网站、大型企业或金融、银行等组织。 以上三种证书都可选单域名,多域名,通用域名3个种类,价格也不同。 单域名:仅保护一个域名的普通SSL证书。 www.centby.com 多域名:可以同时保护多个域名数量可选择,不管是主域名还是子域名都行。 www.centby.com,m.centby.com,porcelain.bbs.centby.com 通用域名:能够保护一个域名以及该域名的所有下一级域名,有范围的限制,但是没有数量的限制。 *.centby.com 或 *.info.centby.com 不可以越级 配置Nginx vi /usr/local/nginx/conf/nginx.conf #user nobody; worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' # '$status $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"'; #access_log logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; #start upstream demoa { #ip_hash; server 127.0.0.1:8000; } upstream demob { #ip_hash; server 127.0.0.1:8001; } #end #start ssl server { listen 443; server_name www.centby.com; ssl on; root /usr/share/nginx/html; ssl_certificate "cert/cert-15_xy.centby.com.crt";##示例 ssl_certificate_key "cert/cert-15_xy.centby.com.key";##示例 ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; ssl_prefer_server_ciphers on; location / { proxy_pass http://demoa; } error_page 404 /404.html; location = /40x.html { } error_page 500 502 503 504 /50x.html; location = /50x.html { } } server { listen 443; server_name m.centby.com; ssl on; root /usr/share/nginx/html; ssl_certificate "cert/cert-8_aapi.crt";##示例 ssl_certificate_key "cert/cert-8_bapi.key";##示例 ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; ssl_prefer_server_ciphers on; location / { proxy_pass http://demob; } error_page 404 /404.html; location = /40x.html { } error_page 500 502 503 504 /50x.html; location = /50x.html { } } #end ssl server { listen 80; server_name www.centby.com; #charset koi8-r; #access_log logs/host.access.log main; #location / { # root html; # index index.html index.htm; # } location / { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_buffering off; proxy_pass http://demoa; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } server { listen 80; server_name m.centby.com; #charset koi8-r; #access_log logs/host.access.log main; #location / { # root html; # index index.html index.htm; # } location / { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_buffering off; proxy_pass http://demob; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } #include vhost/*.conf; } 重启Nginx服务 //进入目录 cd /usr/local/nginx/sbin //测试 ./nginx -t //重启服务 ./nginx -s reload

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。