入門(mén)筆記,大神請(qǐng)繞路?。?!
簡(jiǎn)單的說(shuō) Node.js 就是運(yùn)行在服務(wù)端的 JavaScript。
Node.js 是一個(gè)基于Chrome JavaScript 運(yùn)行時(shí)建立的一個(gè)平臺(tái)。
Node.js是一個(gè)事件驅(qū)動(dòng)I/O服務(wù)端JavaScript環(huán)境,基于Google的V8引擎,V8引擎執(zhí)行Javascript的速度非???,性能非常好。
NodeJS的優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn):
1.高并發(fā)(高并發(fā)的時(shí)候,會(huì)出現(xiàn)數(shù)據(jù)庫(kù)連接數(shù)不夠用的情況,網(wǎng)上還有對(duì)應(yīng)解決方案,還未實(shí)踐)
2.適合I/O密集型應(yīng)用
3.事件驅(qū)動(dòng)、非阻塞I/O、高效、輕量
解決數(shù)據(jù)庫(kù)高并發(fā),程序解決方案:
數(shù)據(jù)庫(kù)高并發(fā)時(shí),連接數(shù)不夠。平臺(tái)監(jiān)聽(tīng)sql操作,如果狀態(tài)是ready
,就回調(diào)執(zhí)行sql操作。相當(dāng)于將sql操作也做異步回調(diào)處理,每次sql操作都是在上次操作ready
后,再執(zhí)行,強(qiáng)制串行執(zhí)行sql操作。這樣就減輕數(shù)據(jù)庫(kù)壓力。但是也可能導(dǎo)致整個(gè)應(yīng)用變慢。
var proxy = new EventProxy();
var status = "ready";
var select = function(callback){
proxy.once("selected",callback);
if(status == "ready"){
status = "pending";
db.select("SQL", function(results){
proxy.emit("selected",results);
status = "ready";
});
}
- 缺點(diǎn):
1.不適合CPU密集型應(yīng)用;
CPU密集型應(yīng)用給Node帶來(lái)的挑戰(zhàn)主要是:由于JavaScript單線(xiàn)程的原因,如果有長(zhǎng)時(shí)間運(yùn)行的計(jì)算(比如大循環(huán)),將會(huì)導(dǎo)致CPU時(shí)間片不能釋放,使得后續(xù)I/O無(wú)法發(fā)起;
解決方案:分解大型運(yùn)算任務(wù)為多個(gè)小任務(wù),使得運(yùn)算能夠適時(shí)釋放,不阻塞I/O調(diào)用的發(fā)起;
2.只支持單核CPU,不能充分利用CPU(可以利用多進(jìn)程利用cpu的,cluster就可以讓你做到nodejs將電腦多核利用起來(lái))
解決方案:
(1)Nnigx反向代理,負(fù)載均衡,開(kāi)多個(gè)進(jìn)程,綁定多個(gè)端口;
(2)開(kāi)多個(gè)進(jìn)程監(jiān)聽(tīng)同一個(gè)端口,使用cluster模塊;
應(yīng)用場(chǎng)景
1. RESTful API
這是NodeJS最理想的應(yīng)用場(chǎng)景,可以處理數(shù)萬(wàn)條連接,本身沒(méi)有太多的邏輯,只需要請(qǐng)求API,組織數(shù)據(jù)進(jìn)行返回即可。它本質(zhì)上只是從某個(gè)數(shù)據(jù)庫(kù)中查找 一些值并將它們組成一個(gè)響應(yīng)。由于響應(yīng)是少量文本,入站請(qǐng)求也是少量的文本,因此流量不高,一臺(tái)機(jī)器甚至也可以處理最繁忙的公司的API需求。
2. 統(tǒng)一Web應(yīng)用的UI層
目前MVC的架構(gòu),在某種意義上來(lái)說(shuō),Web開(kāi)發(fā)有兩個(gè)UI層,一個(gè)是在瀏覽器里面我們最終看到的,另一個(gè)在server端,負(fù)責(zé)生成和拼接頁(yè)面。
不討論這種架構(gòu)是好是壞,但是有另外一種實(shí)踐,面向服務(wù)的架構(gòu),更好的做前后端的依賴(lài)分離。如果所有的關(guān)鍵業(yè)務(wù)邏輯都封裝成REST調(diào)用,就意味著在上層 只需要考慮如何用這些REST接口構(gòu)建具體的應(yīng)用。那些后端程序員們根本不操心具體數(shù)據(jù)是如何從一個(gè)頁(yè)面?zhèn)鬟f到另一個(gè)頁(yè)面的,他們也不用管用戶(hù)數(shù)據(jù)更新是 通過(guò)Ajax異步獲取的還是通過(guò)刷新頁(yè)面。
3. 大量Ajax請(qǐng)求的應(yīng)用
例如個(gè)性化應(yīng)用,每個(gè)用戶(hù)看到的頁(yè)面都不一樣,緩存失效,需要在頁(yè)面加載的時(shí)候發(fā)起Ajax請(qǐng)求,NodeJS能響應(yīng)大量的并發(fā)請(qǐng)求??偠灾?,NodeJS適合運(yùn)用在高并發(fā)、I/O密集、少量業(yè)務(wù)邏輯的場(chǎng)景。
演示一:Hello World!
腳本模式
以下是我們的第一個(gè)Nodejs程序:
console.log("Hello World");
保存該文件,文件名為 helloworld.js
, 并通過(guò) node命令來(lái)執(zhí)行:node helloworld.js
。程序執(zhí)行后,正常的話(huà),就會(huì)在終端輸出 Hello World
。

交互模式
打開(kāi)終端,鍵入node
進(jìn)入命令交互模式,可以輸入一條代碼語(yǔ)句后立即執(zhí)行并顯示結(jié)果,例如:
$ node
> console.log('Hello World!');
Hello World!
image
演示二:nodejs基于http插件,監(jiān)聽(tīng)接口,返回?cái)?shù)據(jù)
1、新建app.js
文件,然后并執(zhí)行執(zhí)行node app.js
。
代碼如下:
var http = require('http');
var server = http.createServer(function (req, res) {
var body = '';
req.on('data', function(data) { // 接收客戶(hù)端發(fā)送過(guò)來(lái)的數(shù)據(jù), 也就是 xmlHttp.send(value);
body += data;
});
req.on('end', function() {
res.writeHeader(200, {
'Content-Type': 'text/plain',
'Access-Control-Allow-Origin': '*' //解決跨域問(wèn)題
});
res.write("hello:" + body);
res.end();
})
});
server.listen(3000, function () {
console.log('server start at localhost:3000');
});
2、找個(gè)引入jquery的頁(yè)面,執(zhí)行post請(qǐng)求:
$.ajax({
url:"http://localhost:3000",
data:"我是快遞小哥,請(qǐng)開(kāi)開(kāi)門(mén)",
type:"post",
success:function(d){console.log("success",d)},
error:function(d){console.log("error",d)}
})
執(zhí)行請(qǐng)求,返回hello:我是快遞小哥,請(qǐng)開(kāi)開(kāi)門(mén)

這個(gè)例子中,nodejs充當(dāng)后臺(tái),app.js中實(shí)現(xiàn)了
http://loadlhost:3000
接口,返回了前端提交的內(nèi)容。
演示三:nodejs基于express插件,監(jiān)聽(tīng)接口,返回?cái)?shù)據(jù)
1、新建service.js
文件,然后執(zhí)行執(zhí)行node service.js
。
代碼如下:
//demo
const express = require('express');
const app = express();
//設(shè)置允許跨域訪(fǎng)問(wèn)該服務(wù).
app.all('*', function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
//Access-Control-Allow-Headers ,可根據(jù)瀏覽器的F12查看,把對(duì)應(yīng)的粘貼在這里就行
res.header('Access-Control-Allow-Headers', 'Content-Type');
res.header('Access-Control-Allow-Methods', '*');
res.header('Content-Type', 'application/json;charset=utf-8');
next();
});
app.post('/hello', function (req, res) {
res.json({title:"你好"});
});
const server = app.listen(8082, function () {
console.log('Express app server listening on port %d', server.address().port);
});
2、找個(gè)引入jquery的頁(yè)面,執(zhí)行post請(qǐng)求:
$.ajax({
url:"http://localhost:8082/hello",
type:"post",
success:function(d){console.log("success",d)},
error:function(d){console.log("error",d)}
})
返回?cái)?shù)據(jù):

演示四:nodejs+express+mysql搭建后端環(huán)境

npm i express -g//安裝express
npm i express-generator -g//安裝命令行工具
express --version//檢測(cè)express是否安裝成功
3、創(chuàng)建express項(xiàng)目
執(zhí)行express express-demo
,新建express項(xiàng)目,文件目錄說(shuō)明:
app.js//啟動(dòng)文件,或者說(shuō)入口文件。新的頁(yè)面以及頁(yè)面相應(yīng)的路由需要在這里配置;
package.json//存儲(chǔ)著工程的信息及模塊依賴(lài),當(dāng)在 dependencies 中添加依賴(lài)的模塊時(shí),運(yùn)行 npm install,npm //會(huì)檢查當(dāng)前目錄下的 package.json,并自動(dòng)安裝所有指定的模塊
node_modules//存放 package.json 中安裝的模塊,當(dāng)你在 package.json 添加依賴(lài)的模塊并安裝后,存放在這個(gè)文件夾下
public//存放 image、css、js 等文件
routes//存放路由文件
views//存放視圖文件或者說(shuō)模版文件
bin//存放可執(zhí)行文件
4、運(yùn)行express項(xiàng)目
cd express-demo//進(jìn)入項(xiàng)目
npm i//安裝依賴(lài)文件
npm start//啟動(dòng)項(xiàng)目
啟動(dòng)成功,空蕩蕩的頁(yè)面中就出現(xiàn)下面內(nèi)容

需要?jiǎng)?chuàng)建以下文件:
model\config.js
:數(shù)據(jù)庫(kù)配置
module.exports = {
mysql: {
host: 'localhost',
user: 'root',
password: '123123',
database: 'nodejs',
port: 3306
}
};
views\login.jade
:登錄頁(yè)面
doctype html
html
head
title
link(href='/stylesheets/style.css', rel='stylesheet')
link(href='/bootstrap-3.3.7/css/bootstrap.min.css', rel='stylesheet')
script(src='/javascripts/jquery.min.js')
script(src='/bootstrap-3.3.7/js/bootstrap.min.js')
body(style='background: #dcd9da')
// h1= title
.container
.row
.col-md-4.col-md-offset-4
.panel.panel-default(style='margin-top: 100px')
.panel-heading(style='background: #0d6aad')
h4(align='center', style='color: #ffffff;')
| express-jade-bootstrap-mysql-demo
.panel-body(style='background: #e0e1ea')
.form-group
.input-group
span.input-group-addon 账号
input#username.form-control(type='text', placeholder='請(qǐng)輸入賬號(hào)')
.form-group
.input-group
span.input-group-addon 密码
input#password.form-control(type='password', placeholder='請(qǐng)輸入密碼')
.form-group
.col-lg-offset-7
| 没有账号?
a(href='/register') 注册
.form-group
button#login.btn.btn-success.btn-block(type='button')
| 登录
#popup.alert.alert-warning
a#close.close(href='#') ×
div(align='center')
strong#popup-content(style='color: #b12e30;')
script(type='text/javascript').
$(document).ready(function () {
var username = $("#username");
var password = $("#password");
var login = $("#login");
var popup = $("#popup");
var popupContent = $("#popup-content");
var close = $("#close");
popup.hide();
close.click(function () {
popup.hide();
});
login.click(function () {
if (username.val() == "" || password.val() == "") {
popup.show();
popupContent.html("賬號(hào)或密碼不能為空!");
} else {
$.ajax({
url: "/login/userLogin",
data: {
username: $("#username").val(),
password: $("#password").val()
},
type: "POST",
timeout: 36000,
dataType: "text",
success: function (data, textStatus) {
//alert(data);
var dataJson = eval("(" + data + ")");
if (dataJson.code == 200) {
alert("登錄成功");
window.location.href = "/";
} else if (dataJson.code == 300) {
popup.show();
popupContent.html("賬號(hào)不存在,請(qǐng)重新輸入!");
} else if (dataJson.code == 400) {
popup.show();
popupContent.html("密碼有誤,請(qǐng)重新輸入!");
} else {
popup.show();
popupContent.html("登錄出錯(cuò)!");
}
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert("error:" + textStatus);
}
}
);
}
})
;
})
;
routes\login.js
:登錄接口邏輯
var express = require('express');
var router = express.Router();
// 實(shí)現(xiàn)與MySQL交互
var mysql = require('mysql');
var config = require('../model/config');
// 使用連接池,提升性能
var pool = mysql.createPool(config.mysql);
/* GET home page. */
router.get('/', function (req, res, next) {
res.render('login', { title: 'login' });
});
router.post('/userLogin', function (req, res, next) {
var username = req.body.username;//獲取前臺(tái)請(qǐng)求的參數(shù)
var password = req.body.password;
pool.getConnection(function (err, connection) {
//先判斷該賬號(hào)是否存在
var $sql = "select * from users where username=?";
connection.query($sql, [username], function (err, result) {
var resultJson = result;
console.log(resultJson.length);
if (resultJson.length === 0) {
result = {
code: 300,
msg: '該賬號(hào)不存在'
};
res.json(result);
connection.release();
} else { //賬號(hào)存在,可以登錄,進(jìn)行密碼判斷
var $sql1 = "select password from users where username=?";
connection.query($sql1, [username], function (err, result) {
var temp = result[0].password; //取得數(shù)據(jù)庫(kù)查詢(xún)字段值
console.log(temp);
if (temp == password) {
result = {
code: 200,
msg: '密碼正確'
};
} else {
result = {
code: 400,
msg: '密碼錯(cuò)誤'
};
}
res.json(result); // 以json形式,把操作結(jié)果返回給前臺(tái)頁(yè)面
connection.release();// 釋放連接
});
}
});
});
});
module.exports = router;
views\register.jade
:注冊(cè)頁(yè)面
doctype html
html
head
title
link(href='/bootstrap-3.3.7/css/bootstrap.min.css', rel='stylesheet')
script(src='/javascripts/jquery.min.js')
script(src='/bootstrap-3.3.7/js/bootstrap.min.js')
body(style='background: #dcd9da')
nav.collapse.navbar-collapse.navbar-inverse
.navbar-header
a.navbar-brand express-jade-bootstrap-mysql-demo
ul.nav.navbar-nav.navbar-right
li(style='margin-right: 20px')
a(href='/login')
span.glyphicon.glyphicon-log-in
| 登录
.container
.row
.col-md-4.col-md-offset-4
.panel.panel-default(style='margin-top: 40px')
.panel-heading(style='background: #0d6aad')
h3(align='center', style='color: #ffffff;')
| 账号注册
.panel-body(style='background: #e0e1ea')
.form-group
.input-group
span.input-group-addon 账 号
input#username.form-control(type='text', placeholder='請(qǐng)輸入賬號(hào)')
.form-group
.input-group
span.input-group-addon 密 码
input#password.form-control(type='password', placeholder='請(qǐng)輸入密碼')
.form-group
.input-group
span.input-group-addon 确认密码
input#password1.form-control(type='password', placeholder='請(qǐng)?jiān)俅屋斎朊艽a')
.form-group
.input-group
span.input-group-addon 姓 名
input#name.form-control(type='text', placeholder='請(qǐng)輸入姓名')
.form-group
button#register.btn.btn-success.btn-block(type='button')
| 注册
#popup.alert.alert-warning
a#close.close(href='#') ×
div(align='center')
strong#popup-content(style='color: #b12e30;')
script(type='text/javascript').
$(document).ready(function () {
var username = $("#username");
var password = $("#password");
var password1 = $("#password1");
var name = $("#name");
var register = $("#register");
var popup = $("#popup");
var popupContent = $("#popup-content");
var close = $("#close");
popup.hide();
close.click(function () {
popup.hide();
});
register.click(function () {
if (username.val() == "" || password.val() == "" || password1.val() == "" || name.val() == "") {
popup.show();
popupContent.html("注冊(cè)信息不能為空!");
} else if (password.val() !== password1.val()) {
popup.show();
popupContent.html("兩次輸入的密碼不一樣!");
} else {
//訪(fǎng)問(wèn)服務(wù)器,將注冊(cè)信息寫(xiě)入數(shù)據(jù)庫(kù)
$.ajax({
url: "/register/userRegister",
data: {
username: $("#username").val(),
password: $("#password").val(),
name: $("#name").val()
},
type: "POST",
timeout: 36000,
dataType: "text",
success: function (data, textStatus) {
var dataJson = eval("(" + data + ")");
if (dataJson.code == 200) {
alert("注冊(cè)成功");
window.location.href = "/login";
} else if (dataJson.code == 300) {
popup.show();
popupContent.html("該賬號(hào)已存在!");
} else if (dataJson.code == 400) {
popup.show();
popupContent.html("注冊(cè)失敗,請(qǐng)重新注冊(cè)!");
} else {
popup.show();
popupContent.html("注冊(cè)出錯(cuò)!");
}
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert("error:" + textStatus);
}
});
}
});
});
routes\register.js
:注冊(cè)接口邏輯
var express = require('express');
var router = express.Router();
// 實(shí)現(xiàn)與MySQL交互
var mysql = require('mysql');
var config = require('../model/config');
// 使用連接池,提升性能
var pool = mysql.createPool(config.mysql);
/* GET home page. */
router.get('/', function (req, res, next) {
res.render('register', { title: 'register' });
});
router.post('/userRegister', function (req, res, next) {
var username = req.body.username;
var password = req.body.password;
var name = req.body.name; //獲取前臺(tái)請(qǐng)求的參數(shù)
pool.getConnection(function (err, connection) {
//先判斷該賬號(hào)是否存在
var $sql = "select * from users where username=?";
connection.query($sql, [username], function (err, result) {
var resultJson = result;
console.log(resultJson.length);
if (resultJson.length !== 0) {
result = {
code: 300,
msg: '該賬號(hào)已存在'
};
res.json(result);
connection.release();
} else { //賬號(hào)不存在,可以注冊(cè)賬號(hào)
// 建立連接,向表中插入值 數(shù)據(jù)庫(kù)表名為user-info會(huì)出錯(cuò)
var $sql1 = "INSERT INTO users(id, username, password, name) VALUES(0,?,?,?)";
connection.query($sql1, [username, password, name], function (err, result) {
console.log(result);
if (result) {
result = {
code: 200,
msg: '注冊(cè)成功'
};
} else {
result = {
code: 400,
msg: '注冊(cè)失敗'
};
}
res.json(result); // 以json形式,把操作結(jié)果返回給前臺(tái)頁(yè)面
connection.release();// 釋放連接
});
}
});
});
});
module.exports = router;
app.js
:修改代碼
...
var login = require("./routes/login");
var register = require("./routes/register");
...
app.use('/login', login);
app.use('/register', register);
...
jquery.min.js
:引入jquery,放到public文件夾bootstrap
:引入bootstrap,放到public文件夾文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-410329.html
準(zhǔn)備好以上代碼后,執(zhí)行
npm start
命令啟動(dòng)項(xiàng)目,打開(kāi)登錄頁(yè)面:http://localhost:3000/login
,注冊(cè)頁(yè)面:http://localhost:3000/register
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-410329.html


參考: NodeJs+Express+SqlServer簡(jiǎn)易后臺(tái)API服務(wù)搭建