入门node.js笔记&结合AWS-lambda遇到的坑及解决

运行

node 是一个单进程单线程的东西。但是可以用回调来异步使用。

首先需要下载node.pkg  去官网下就行了。然后配置环境变量。把这个红框的加进去就行了。

/etc/profile /etc/paths ~/.bash_profile ~/.bash_login ~/.profile ~/.bashrc   这个是系统配置的路径。 当前配的~/.bash_profile

node.js 要想命令行运行一个js 就用  node  xxx.js命令     node -v   npm -v 看版本。  

想创建一个项目没有package.json需要 npm init 这样就会创建一个 package.json 刚开始我以为这个是跟npm或者node绑定的一个json配置文件,后来发现这个东西是每一个项目都存在,都不一样的一个文件。你需要有这个文件才能使用 npm install xx 命令。

npm install 会在当前目录创建一个 node_modules 文件夹。这个就相当于你Java导的jar包似的。

要想命令行玩,node 进入命令行 然后该怎么编码怎么编码。

两下  control+c 退出命令行模式。

让我们先了解下 Node.js 应用是由哪几部分组成的:

1.引入 required 模块:我们可以使用 require 指令来载入 Node.js 模块。

2.创建服务器:服务器可以监听客户端的请求,类似于 Apache 、Nginx 等 HTTP 服务器。

3.接收请求与响应请求 服务器很容易创建,客户端可以使用浏览器或终端发送 HTTP 请求,服务器接收请求后返回响应数据。

所以一个node项目是需要写一个服务器的。

//我们使用 require 指令来载入 http 模块,并将实例化的 HTTP 赋值给变量 http
var http = require("http");

http.createServer(function (request,response) {
    response.writeHead(200,{"Content-Type":"text/plain"});
    response.end("hello zhanghong this is send message \n");

}).listen(8989);

console.log("server is running");

npm

npm -v 看版本。   sudo npm install npm -g 更新。  这个npm有种 maven的感觉。

npm install  module_name 安装指定模块。    npm  install  xxx@1.1.0   指定版本号否则安最新的。  npm list 看导入的包。

npm有两种形式的安装。全局安装和非局部安装(本地安装)。

npm install  module_name  -g   差就差在这个 -g命令。

npm cache clear  --force   清除本地缓存。

非全局的安装  需要你当前目录有package.json文件。没有会报错。 npm  init 会在当前目录下创建package.json文件。

有了这个文件就可以安装node_modules了。

使用时用这个require命令来引入包。然后获取这个包的实例。通过实例来操作这个包的方法。var http = require("http");

这个个人理解的就像Java中 import包。但是这个导包需要有一个实例接收。这个实例能使用方法。可以理解为都是实例方法。

npm  uninstall module 卸载模块。

这种方式的安装,只有这个项目是可见的。其他项目是看不见这个module。相当于Java中的maven。每个项目不一样。

全局安装  sudo npm install express -g   最好加sudo  要不可能会报错。可以看到我这个express模块全局安装到了npm同级目录。

下面还会做出关于全局非全局的叙述。

package.json

配置文件。首先这个里面不要写注释。会报错。  下面是属性说明。文末赋参考链接。

name   这个属性  要全部小写 无空格    version 就是  x.x.x 这样

keywords 这个关键字就是你在  npm  search xxx 时候用的

main 入口函数。就像springboot中的  @springbootApplication注释的类似的。

script 默认有一个test.    这个是你  npm  run  xxx.js 来直接运行的。

dependencies 这个就是依赖的jar。相当于pom 可以指定版本号。生产环境。

devDependencies 这个是在开发环境上指定的jar。

关于dependencies中的jar的版本有一些说到。分为大版本,小版本,补丁版本。

如果允许随着版本的更新而更新前面就可以加一些符号。  ~表示接受补丁版本的更新,^表示接受小版本的更新,*表示接受大版本的更新,这个更新可能会存在一些问题,严重可能会导致你的接口随着版本的变更调不通。

~1.1.0    ^1.1.0   *

对于非全局的package.json。也就是你的项目中的package 里面的依赖通过  npm  install 安装到 这个package关联的node_modules中。这个npm  install 会安装所有的依赖到你的项目modules中。如果只安装dependencies的你可以用 npm install --production

所以在项目中最好拿过来先  npm install 一下、   

install完了。你的modules中就有这些模块了。然后你就可以run了。在使用的地方通过 require() 引用实例。

对于全局的操作。命令加了  -g 

注意:在你npm  install module_name 安一个包后。你得在package中加入它。  或者你选择一个更酷的方式,用命令行。

npm install module_name  --save 安装这个模块并把package.json中的dependencies也写上。   

(--save-dev)是写到 devDependencies里。  下面是一个新的项目中。测试 save的例子。

先 npm init  在  npm install module_name  --save 发现好用。

你也可以用npm  update 来更新你的modules  但是注意你的package中的dependencies设置  ~ ^ *  否则更新不一定如愿。

REPL(交互式解释器)

这个简单运算就不说了。跟Java  js  差不多。

提一下  _  下划线。这个下划线是获取上一个表达式的结果。

回调函数

语法:function foo1(name, age, callback) { }                function foo2(value, callback1, callback2) { }

var fs = require("fs");

var data = fs.readFileSync('input.txt');

console.log(data.toString());
console.log("程序执行结束!");

下面为创建过程与执行结果。

var fs = require("fs");

fs.readFile('input.txt', function (err, data) {
   if (err){
      console.log(err.stack);
      return;
   }
   console.log(data.toString());
});
console.log("程序执行完毕");

这个是异步执行。回调函数 err参数是错误对象。执行异步操作的函数将回调函数作为最后一个参数, 回调函数接收错误对象作为第一个参数。

事件循环

通过events模块来操作事件。

var events = require('events'); //获取events实例

var eventEmitter = new events.EventEmitter();// 创建 eventEmitter 对象

这个eventEmitter 有两个操作。绑定事件。触发事件。

eventEmitter.on("eventName", eventHandler());  // 这个是声明eventName事件被触发时调用这个处理器。即执行eventHandler代码。这个相当于声明了一下,等待被emit触发。

eventEmitter.emit('eventName');  //这个是触发事件的意思。就是触发eventName事件。

例子  引自文末链接。

// 引入 events 模块
var events = require('events');
// 创建 eventEmitter 对象
var eventEmitter = new events.EventEmitter();

// 创建事件处理程序
var connectHandler = function connected() {                  //2.触发connection后调用这个处理器。
    console.log('连接成功。');                                 //第一个输出。

    // 触发 data_received 事件
    eventEmitter.emit('data_received');                      //触发data_received事件
}

// 绑定 connection 事件处理程序
eventEmitter.on('connection', connectHandler);

// 使用匿名函数绑定 data_received 事件
eventEmitter.on('data_received', function(){                 //3.触发data_received事件调用这个处理器。
    console.log('数据接收成功。');                             //第二个输出
});

// 触发 connection 事件
eventEmitter.emit('connection');                            //1.此处为第一次触发事件。触发connection

console.log("程序执行完毕。");                                //第三个输出。

这个handler里面也可以设置形式参数。在emit的时候传入实参就行了。对于一个事件绑定的多个handler 按顺序执行。eventEmitter.listenerCount(''eventName");  来获取这个事件的监听handler数量。

试想。要是一个事件触发另一个事件。另一个事件又触发这个事件,是不是就死循环了。

包括 fs、net、 http 在内的,只要是支持事件响应的核心模块都是 EventEmitter 的子类。

模块系统

node.js提供了exports和require 这两个对象来操作模块之间的联系。

其中 exports 是模块公开的接口,require 用于从外部获取一个模块的接口,即所获取模块的 exports 对象。

两个模块来说。就是俩js

first.js   代码如下。

function interfaceMethod() {
    console.log("this is first method");
}

exports.interfaceFirst=interfaceMethod   //暴露interfaceFirst 方法执行interfaceMethod处理器。

second.js

var first = require("./first");
first.interfaceFirst();
console.log("this is second js")

node second.js输出结果

路由

我们要为路由提供请求的 URL 和其他需要的 GET 及 POST 参数,随后路由需要根据这些数据来执行相应的代码。

server.js

var http = require('http');
var url = require('url');
console.log("access")
function startServer(route) {
    function onRequest(request, response) {            //这么写就得用路由访问了。要不执行不了。
        var pathname = url.parse(request.url).pathname;     //获取路径。
        console.log("Request for " + pathname + " received.");

        route(pathname);  //将请求路径传入路由。

        response.writeHead(200, {"Content-Type": "text/plain"});
        response.write("Hello World");
        response.end();
    }

    http.createServer(onRequest).listen(8888);//入参为function 也可以写匿名函数。由于使用路由就不用匿名函数了。
    console.log("Server has started.");
}

exports.start = startServer;     //模块间暴露接口start 调用本类的startServer

router.js

function route(pathname) {
    console.log("About to route a request for " + pathname);
}

exports.routeMethod = route;     //暴露路由的接口

index.js

var route = require("./router");
var server = require("./server");


console.log("this is index js")

server.start(route.routeMethod)

下面是输出的结果。可以看到先输出 access 也就是先进入服务器server类。执行到onRequest时阻塞   输出index类中的代码。然后输出server has  received  可以看到  当我们没访问8888端口时 onRequest方法中没有输出。只是服务器启起来了。

下面是我分别访问 /  /test 的结果。可以看出此时只要访问8888端口就会输出。所以这个pathname我们可以进行分发。

这个在使用express的web模块时会有很大的改善。包括 path的分发。可以参考 这个地址

GET/POST

下面的类是用util的inspect方法获取到的URL所有能获取的信息

var http = require("http");
var url = require('url');
var util = require('util');

http.createServer(function (request,response) {
    response.writeHead(200,{"Content-Type":"text/plain; charset=utf-8"});
    response.end(util.inspect(url.parse(request.url, true)));

}).listen(8888);

一般HTTP请求常使用的是URL的query参数和body参数。下面是获取URL的 query参数

var http = require("http");
var url = require('url');
var util = require('util');

http.createServer(function (request,response) {
    response.writeHead(200,{"Content-Type":"text/plain; charset=utf-8"});

    var params = url.parse(request.url, true).query;  //获取到查询参数。
    response.write("网站名:" + params.name);
    response.write("\n");
    response.write("网站 URL:" + params.url);

    response.end();
    //util.inspect(url.parse(request.url, true))
}).listen(8888);

下面是body体的使用。

var http = require("http");
// var url = require('url');
// var util = require('util');
var querystring = require('querystring');

http.createServer(function(req, res){
    // 定义了一个post变量,用于暂存请求体的信息
    var post = '';

    // 通过req的data事件监听函数,每当接受到请求体的数据,就累加到post变量中
    req.on('data', function(chunk){
        post += chunk;
    });

    // 在end事件触发后,通过querystring.parse将post解析为真正的POST请求格式,然后向客户端返回。
    req.on('end', function(){
        post = querystring.parse(post);
        res.end(util.inspect(post));
    });
}).listen(8888);

这部分就不多赘述了。

全局变量

在浏览器 JavaScript 中,通常 window 是全局对象, 而 Node.js 中的全局对象是 global,所有全局变量(除了 global 本身以外)都是 global 对象的属性。

在 Node.js 我们可以直接访问到 global 的属性,而不需要在应用中包含它。

console.log("global >>>>>>" + global + "\n");
//表示当前正在执行的脚本的文件名。它将输出文件所在位置的绝对路径,且和命令行参数所指定的文件名不一定相同。 如果在模块中,返回的值是模块文件的路径
console.log("_filename >>>>>>" + __filename + "\n");
//_dirname 表示当前执行脚本所在的目录。
console.log("_dirname >>>>>>" + __dirname + "\n");   //注意是俩下划线。
var timer = setTimeout(function () {
    console.log("this is setTimeout print" + "\n");
},1000)     //单位ms
// clearTimeout(timer); //这个跟js用法差不多。
var timer2 = setInterval(function () {
    console.log("this is setInterval print \n");
})
clearInterval(timer2);
// 还有 Process 这个属性能与OS交互。

下面是输出的结果。

Util类

这个类就像Java里面的util似的。是一个封装一些常用方法的工具类。

var util = require('util');   需要引入这个模块。

说两个简单的用法吧。转成字符串输出 和 判断是不是数组。

var util = require('util');
var array = [1, 2, 3, 4, 5, 6]
var isArray = util.isArray(array);
console.log("is array ?  >>>>>>" + isArray);
console.log("array >>>>>" + util.inspect(array))

AWS-Lambda + node.js 遇见的坑

关于错误截图就不加了,进行文字描述。

1.学习这个node.js  是有个需求做  echarts + canvas 的图片生成。于是我就开始接触这个东西。

第一个坑是按完不知道npm 咋用   就在一个随便的目录下使用npm install  然后发现报 not found package.json 类似错误。

然后发现得在该项目下面先  初始化 package.json 文件。  npm init   这样才能保证npm install 正常运行。

2.然后接下来就是装canvas  的一系列错。 打算把这个东西扔到  AWS-Lambda 上。这个部署包必须要求在 Linux环境下编译出来的。我之前是在  mac os 10.13 编译的 。扔上去就报错。然后放到 Linux 下面编译 还出了一系列问题。

第一个问题是  xxxx/dir    permission  这么一个 错。  这样canvas 是装不成功的 。  我先  npm install --unsafe-perm 发现还是不行

于是我把这个项目中的 node_modules 设置成了 chmod  -R 777  XXX 权限。  这个权限其实还是很有问题的。权限太高了。为了测试  这么提权后 确实可行。

3.然后我部署的时候又出现一个问题。就是   NODE_MODULE_VERSION 57    NODE_MODULE_VERSION 67  这么一个错误。这个错误就是编译版本不一致导致的 lambda 不能成功执行 node.js 代码 。于是我找到一个方法解决这个问题。 npm rebuild --abi=67 这样就编译指定二进制接口的版本。最后 zip 打包扔上去就好使了 。

4.还有一个问题就是这个lambda的返回结果是一个Json,所以是不能设置成content-type的。然后我是通过返回base64图片编码来解决这个事情。 前端还需要做相应的解码操作。

 

 

 

参考:https://blog.csdn.net/u011240877/article/details/76582670

 

声明:本文是在这个网站学习node.js记录下来的笔记。部分内容摘自:  http://www.runoob.com/nodejs

 

刚刚入门这个node.js  因为常使用Java,然后有一个需求需要用到这个node.js就学习了一下。本文的内容还很浅。等有时间会深入了解一下这门语言。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值