2019-07-24 | 学习笔记 | UNLOCK | 更新时间:2022-10-8 9:56

Node.js的学习笔记(一).md

项目的开启

由于Node.js的内容和API过于繁杂,只能先简单的过一遍在实际使用中慢慢加深学习,那么就从简单的基础应用开始,以连接数据库,增删查改,编写接口开始

npm init

初始化一些项目的基础信息,填写好之后,项目就算开始了

开发环境的配置

安装数据库相关

安装 MySql(选项一),建表,配置约束建

我之前看了下MySQL 没仔细研究,只能先用可视化工具 phpmyadmin 先用着,等熟悉后在考虑命令编辑的问题,我使用的是 WAMPSERVER 的集成环境,安装好数据库后,登陆 phpmyadmin【 http://localhost/phpmyadmin 】 再创建要用到的表,这里就不仔细讲了,

npm install mysql

安装mysql 配套模块,node需要 mysql 模块对数据库进行连接,

安装SQLite , 建表

npm install sqlite3 –save

安装热更新模块

npm install nodemon

package.json
··· "scripts": { "serve": "nodemon index.js", "test": "echo \"Error: no test specified\" && exit 1" }, ····

在 node 项目开发中,每次更新都要手动更新一遍服务器,相当麻烦,所以迫切需要热更新模块来解决手动更新的麻烦。安装好后,在package.json 里配置 自定义命令,之后执行 启动命令 npm serve 就好了

安装Express 模块

npm install express –save

安装 Express 并将其保存到依赖列表中,还需要安装下列几个重要模块

  • body-parser - node.js 中间件,用于处理 JSON, Raw, Text 和 URL 编码的数据。
  • cookie-parser - 这就是一个解析Cookie的工具。通过req.cookies可以取到传过来的cookie,并把它们转成对象。
  • multer - node.js 中间件,用于处理 enctype=”multipart/form-data”(设置表单的MIME编码)的表单数据

npm install body-parser –save
npm install cookie-parser –save
npm install multer –save

这几个模块作为重要模块,具体的使用可以看官方文档或参考我的使用

express 是一个基于node的 web开发模块,可以基于 express 来引入中间件或是其他需要

可选安装模块

log4js 日志管理模块

npm install log4js

# 入口配置

...
const log4js = require('log4js');
log4js.configure({
  appenders: { cheese: { type: 'file', filename: 'cheese.log' } },
  categories: { default: { appenders: ['cheese'], level: 'trace' } }
})
...

# appenders:以 file 的形式将日志记录在 cheese.log 中
# categories:将错误级别记录在 cheese 配置中

当项目开始运行的时候,很多时候管理人员需要对项目的运行状态进行检查,需要知晓项目的运作情况,这个时候就需要一个日志记录器.默认情况下,不会进行日志输出,需要在入口js 中进行配置。具体的配置可以查看官网文档参考我的使用

node 的入口文件

设置一个入口文件 index.js,在最开始的时候执行。

index.js
const express=require('express') const Router=require('./router') //路由文件 const Inter=require('./Interface')//接口文件 const bodyParser = require('body-parser') const log4js = require('log4js'); //日志配置 log4js.configure({ appenders: { cheese: { type: 'file', filename: 'cheese.log' } }, categories: { default: { appenders: ['cheese'], level: 'trace' } } }); const app=express(); // app.use(bodyParser.json()); app.use(bodyParser.urlencoded({extended: false})); const server=app.listen(8888,()=>{ logger.trace('服务器启动,正在监听8888端口'); }) //接口 Inter.api(express,app) //路由 Router.middle(express,app)

接口的编辑

Interface.js
... const api=((express,app)=>{ const mysql=require('mysql'); const connection=mysql.createConnection({ //连接 mysql 的配置 host :'localhost', user :'root', password :'', // port: '8888', database :'mysql' }); connection.connect() //查询接口 app.get('/list',(require,response,next)=>{ let name=require.query.name let sql='SELECT * FROM websites'; if(name){ sql = "SELECT * FROM websites WHERE name LIKE "+mysql.escape(name) } // 执行数据库命令,按返回的数据返回状态 connection.query(sql,function (err, result) { if(err){ response.status(500).json({ code:500, message:err.toString() // message:"数据库查询出错!" }) logger.error(err.toString()); return } response.json([ ...result ]); response.end(); }) }) }) ...

至此一个简单的应用就算是好了,但是如果想要运用在实践上,那么还需要考虑更细化的问题,返回的状态协议,上传文件的处理,sql反注入以及日志的细化处理,中间件的处理,路由的一系列处理等等。当然一个好的开始总是好的,剩下的问题可以看后面的笔记以及附录。

可能出现的问题

怎么建立约束键?

在 phpmyadmin 中,约束键是表与表之间的关联,它们可以都是主键,首先在表的-操作界面-将表的存储引擎设置为InnoDB,排序规则调整为utf8_general_ci。然后进入数据库的-设计器界面-选择左侧的创建关系,最后选择两个表的字段连接,填写删除和更新配置:cascade(级联:在父表数据被删除后,子表对应数据也被删除) set Null(在父表数据被删除后,子表对应数据设置为null) no action(不采取行动) RESTRICT(在删除父表数据的时候,如有关联,禁止删除)

Nodejs的应用

Nodejs由下列部分组成

  • 1:引入required模块(使用require指令载入node模块)
  • 2:创建服务器 (服务器可以监听客户端请求,类似apache)
  • 3:接收请求和响应数据 (接受请求,返回数据)
// 引入required模块
var http = require('http');

// 创建服务器
http.createServer(function(request,response){

  // 发送 HTTP 头部 
  // HTTP 状态值: 200 : OK
  // 内容类型: text/plain
  response.writeHead(200, {'Content-Type': 'text/plain'});
  // 发送响应数据 "Hello World"
  response.end('Hello World\n');

}).listen(8888);

// 终端打印如下信息
console.log('Server running at http://127.0.0.1:8888/');

第一行请求(require)Node.js 自带的 http 模块,并且把它赋值给 http 变量。
接下来我们调用 http 模块提供的函数: createServer 。这个函数会返回 一个对象,这个对象有一个叫做 listen 的方法,这个方法有一个数值参数, 指定这个 HTTP 服务器监听的端口号。

NodeJS的模块系统

为了让Node.js的文件可以相互调用,Node.js提供了一个简单的模块系统,一个 Node.js 文件就是一个模块

//hello.js 
function Hello() { 
    var name; 
    this.setName = function(thyName) { 
        name = thyName; 
    }; 
    this.sayHello = function() { 
        console.log('Hello ' + name); 
    }; 
}; 
module.exports = Hello;

//main.js 
var Hello = require('./hello'); 
hello = new Hello(); 
hello.setName('BYVoid'); 
hello.sayHello();

npm 及相关的模块

NPM是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题.express是常用的 Node.js web框架模块

$ npm install express

NPM的一些常用命令和使用技巧……

event 模块

events 模块只提供了一个对象: events.EventEmitter。EventEmitter 的核心就是事件触发与事件监听器功能的封装

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

// 绑定事件及事件的处理程序
eventEmitter.on('eventName', eventHandler);

eventEmitter.on('someEvent', function(arg1, arg2) { 
    console.log('listener1', arg1, arg2); 
}); 

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

fs.readFile 模块

fs.readFile() 是异步函数用于读取文件;如果在读取文件过程中发生错误,错误 err 对象就会输出错误信息。
如果没发生错误,readFile 跳过 err 对象的输出,文件内容就通过回调函数输出

var fs = require("fs");

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

Buffer(缓存区) 模块

JavaScript 语言自身只有字符串数据类型,没有二进制数据类型,为了处理二进制数据,因此在定义了Buffer类型
Node 目前支持的字符编码:

  • ascii - 仅支持 7 位 ASCII 数据。如果设置去掉高位的话,这种编码是非常快的。
  • utf8 - 多字节编码的 Unicode 字符。许多网页和其他文档格式都使用 UTF-8 。
  • utf16le - 2 或 4 个字节,小字节序编码的 Unicode 字符。支持代理对(U+10000 至 U+10FFFF)。
  • ucs2 - utf16le 的别名。
  • base64 - Base64 编码。
  • latin1 - 一种把 Buffer 编码成一字节编码的字符串的方式。
  • binary - latin1 的别名。
  • hex - 将每个字节编码为两个十六进制字符。
// 创建一个长度为 10、且用 0 填充的 Buffer。
const buf1 = Buffer.alloc(10);
// 创建一个长度为 10、且用 0x1 填充的 Buffer。 
const buf2 = Buffer.alloc(10, 1);

// 创建一个长度为 10、且未初始化的 Buffer。
// 这个方法比调用 Buffer.alloc() 更快,
// 但返回的 Buffer 实例可能包含旧数据,
// 因此需要使用 fill() 或 write() 重写。
const buf3 = Buffer.allocUnsafe(10);

// 创建256长度的的buffer,然后重写
buf = Buffer.alloc(256);
len = buf.write("www.runoob.com");
console.log("写入字节数 : "+  len);

REPL(交互式解释器)

node自带交互式解释器,它可以读取(读取用户输入),执行(执行输入的数据结构),打印(输出结果),循环(循环操作以上步骤直到用户两次按下 ctrl-c 按钮退出).Node 的交互式解释器可以很好的调试 Javascript 代码

// 启动终端
$ node

// 它可以执行简单的运算表达式,变量和多行表达式
> 1+2

>do {
... x++;
... console.log("x: " + x);
... } while ( x < 5 );

NodeJS 的路由

我们要为路由提供请求的 URL 和其他需要的 GET 及 POST 参数,随后路由需要根据这些数据来执行相应的代码
为了解析这些数据,我们需要额外的 Node.JS 模块,它们分别是 url 和 querystring 模块

server.js

var http = require("http");
var url = require("url");
 
function start() {
  function onRequest(request, response) {
    var pathname = url.parse(request.url).pathname;
    console.log("Request for " + pathname + " received.");
    response.writeHead(200, {"Content-Type": "text/plain"});
    response.write("Hello World");
    response.end();
  }
 
  http.createServer(onRequest).listen(8888);
  console.log("Server has started.");
}
 
exports.start = start;

router

function route(pathname) {
  console.log("pathname"  + pathname);
}
 
exports.route = route;

index.js

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

Node 静态文件服务

通过创建服务,将文件资源挂载在服务上;

// var http = require('http');
// var fs = require('fs');
// var url = require('url');
// var path = require("path")
// var c = require('child_process');

import http from 'http';
import fs from 'fs';
import url from 'url';
import path from "path";
import c from 'child_process';

// 创建服务器
http.createServer( function (request, response) { 
   // 解析请求,包括文件名
   var pathname = url.parse(request.url).pathname;
   var extname = path.extname(pathname);
   // 输出请求的文件名
   // console.log("Request for " + pathname + " received.");
   
   // 从文件系统中读取请求的文件内容
   fs.readFile(pathname.substr(1), function (err, data) {
        let type = memu(extname);
        if (err) {
           response.writeHead(404, {'Content-Type': type});
        }else{             
           response.writeHead(200, {
              'Content-Length': data.length,
              'Content-Type': type
           });    
           
           // 响应文件内容
           response.write(data);        
        }
        //  发送响应数据
        response.end();
   });   
}).listen(9000);
c.exec('start http://localhost:9000/index.html');

function memu(exname){
    switch(exname){
        case ".html":
            return "text/html";
            break;
        case ".css":
            return "text/css";
            break;
        case ".jpg":
            return "image/jpg";
            break;
        case ".png":
            return "image/png";
            break;
        case ".js":
            return "text/javascript";
            break;
        case ".json":
            return "text/json";
            break;
        case ".jpeg":
            return "image/jpeg";
            break;
        case ".gif":
            return "image/gif";
            break;
        case ".svg":
            return "image/svg+xml";
            break;
        case ".rtf":
            return "application/rtf";
            break;
        case ".woff":case ".woff2":
            return "application/x-font-woff";
            break;
        case ".webm":
            return "video/webm";
            break;
        default:
            return "text/plain";
    }
}

// 控制台会输出以下信息
console.log(' \n \
请勿关闭本窗口,打开浏览器访问下列地址  \n\
');
console.log(' http://localhost:9000/index.html')