项目的开启
由于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
···
"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,在最开始的时候执行。
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)
接口的编辑
...
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')