NodeJS
本文需要一點html、js基礎更容易看懂
但我寫的巨簡單不會應該問題也不大
首先node.js一些理論知識,這個自己看一下官方文檔
0. 官方api
1.檔案操作
1.1 讀取檔案
注意
error
和
data
的位置固定
require
是node的核心子產品,可填url、fs、os、http、path等
官方path子產品文檔
從檔案中讀取到的一定是字元串,不會是對象
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnL3QDO4ETMwMjMwMTMwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
1.2 寫檔案
隻有error參數
當同時需要讀寫時,因為js讀寫是異步的,是以直接寫是一定失敗的,錯誤如下
解決方法
把寫檔案的操作放到讀檔案傳回結果之後
2.HTTP
結果如圖
//簡化寫法
var handsomewu = require('http');
var server = handsomewu.createServer();
handsomewu.createServer('request',function (request,response){
console.log('get request')
response.end('Handsome Wu is coming')
})
.listen(3000,function (){
console.log("started")
})
以上代碼隻能無關路徑隻能傳回同一個值,想要對不同的請求路徑傳回不同值可以對request的url進行判斷
request.url
,根據不通過值傳回不同結果,注意傳回值隻能是字元串或二進制資料
傳輸中文時因解碼方式不一樣會出現亂碼,解決方法:
http.serHeader('Content-Type','text/plain;charset=UTF-8')
//如果傳回的是html标簽則把plain改為html即可
//更多類型可參照content-type對照表
以下方法可實作任意目錄都可傳回,無需判斷路徑
var HandsomeWu = require('http');
var server = HandsomeWu.createServer();
var MyDir = 'D:\\code\\web\\LearnNodeJS';
server.on('request', function (request, response) {
var path = '/index.html';
console.log(request.url)
if (request.url !== '/') {
path = request.url;
}
fs = require('fs');
fs.readFile(MyDir + path, function (err, data) {
if (err) {
response.end('404 Not Found');
} else {
response.end(data)
}
})
})
server.listen(3000, function () {
console.log("started")
})
3.Imports&Exports
Exports不但可以傳回變量,同時支援傳回方法,傳回的是一個對象
exports.add = function (a, b) {
return a + b;
}
//如果隻是想直接傳回一個東西,可以使用以下方法,寫兩次的話是覆寫
modual.exports = add;
以上的原理是:每個子產品中都會有一個modual對象,exports是modual對象的一個子對象,為了友善,子產品中
exports被認為是modual.exports,是以其實每次傳回的都是modual.exports對象,但是如果直接對exports
指派,即exports='hello'這樣,會導緻産生新的位址空間,即exports和modual.exports指向的不是同一個
對象,是以不可直接指派
4.服務端渲染
4.1 服務端渲染和用戶端渲染的差別
4.1 服務端渲染和用戶端渲染的差別
1.用戶端渲染不利于SEO搜尋引擎優化
2.服務端渲染是可以被爬蟲抓取到的,用戶端異步渲染是很難被爬蟲抓取到的
3.是以你會發現真正的網站既不是純異步也不是純服務端渲染出來的而是兩者結合來做的
4.例如京東的商品清單就采用的是服務端渲染,目的了為了SEO搜尋引擎優化,而它的商品
評論清單為了使用者體驗,而且也不需要SEO優化,是以采用是用戶端渲染(ajax)
4.2 以下代碼以art-template為例做服務端渲染,基本使用步驟和小程式渲染沒什麼差別
4.2 以下代碼以art-template為例做服務端渲染,基本使用步驟和小程式渲染沒什麼差別
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Node.js Only</title>
</head>
<body>
{{body}}
<!--以下為循環渲染寫法-->
<!--{{each body}}-->
<!--name:{{$value.name}}-->
<!--</br>-->
<!--age:{{$value.age}}-->
<!--</br>-->
<!--sex:{{$value.sex}}-->
<!--{{/each}}-->
</body>
</html>
var http=require('http')
var template=require('art-template');
var fs=require('fs');
var server=http.createServer();
server.on('request',function (request,response){
fs.readFile('./Files/index.html',function (err,data){
if(err){
return console.log('404 not found');
}
var ret=template.render(data.toString(),{
body : 'Hello Handsome Wu'
})
response.end(ret)
})
})
server.listen(3000,function (){
console.log("started")
})
5.處理查詢請求
用戶端進行查詢後url會像這樣
https://editor.csdn.net/md?articleId=113448490
,如果直接在服務端請求路徑的話無法區分出url和?後面的部分,是以引用
url子產品
具體操作如下
var handsomewu = require('http');
var url=require('url');
var server = handsomewu.createServer();
server.on('request', function (request, response) {
console.log('get request')
//請求示例路徑:192.168.137.1:3000/index.html?name=123
//不加任何操作得到的url為:/index.html?name=123
PathNameObj=url.parse(request.url,true)
//true表示把字元串轉為對象
response.end(PathNameObj.pathname)
//以上操作後獲得的值為/index.html
//通過.query對象可獲得表單送出的資料
})
server.listen(3000, function () {
console.log("started")
})
此處注意一點,預設的表單送出行為(即form的action屬性)需要在每個input裡面加上name屬性,否則送出的資料中不會顯示,而且用form送出的資料是經過編碼的
6.Express
基本代碼示例:
var express=require('express');
var app=express();
//開放整個public目錄,無需對該目錄下的檔案處理,可以直接打開
//前一個public可任由自己更改,後一個為檔案夾路徑,不能改
app.use('/public/',express.static('./public/'))
app.get('/',function (req,res){
res.send('請求到的是'+req.url)
})
app.listen(3000,function (){
console.log('start')
})
express中會直接處理查詢請求,例如隻是寫了
/
路徑的請求但是他會主動處理例如
/?name=HandsomeWu
,擷取key和value隻需要使用
req.query
(此方法僅限于get,post不适用)即可獲得json資料
6.1 Express-art-template
極簡示例代碼
var express = require('express');
var app = express();
//這裡的html是指檔案的字尾名,這裡填什麼傳回的檔案的字尾名就應該是什麼,
app.engine('html', require('express-art-template'));
/*
*Express-art-template預設傳回的路徑是在views目錄下的東西,是以直接寫
*檔案的話傳回的時view目錄下的檔案,且可以直接帶渲染的資訊
*/
app.get('/', function (req, res) {
res.render('demo.html',{
title:' is 20 years old'
})
});
6.2 解析擷取post表單請求體
在express中,沒有内置擷取表單 POST 請求體的 API,這裡我們需要使用一個第三方包:
body-parser
先安裝再引包即可
npm install --save body-parser
var express = require('express')
//引包
var bodyParser = require('body-parser')
var app = express()
// 配置 body-parser 中間件
// 隻要加入這個配置,在 req 請求對象上會多出來一個屬性:body
// 也就是說可以直接通過 req.body 來擷取表單 POST 請求體資料了
app.use(bodyParser.urlencoded({extended : false}))
app.use(bodyParser.json())
//擷取調用
app.post('/post',function (req,res){
console.log(req.body)
})
6.3 路由子產品提取
使用express自帶的一個api即可
app.js
var express=require('express');
//引包
var router=require('./router')
var app=express();
app.engine('html', require('express-art-template'));
//核心語句,把app作為參數傳入
router(app);
app.listen(3000,function (){
console.log('start')
})
module.exports=app;
router.js
//直接把整個作為方法輸出
module.exports=function (app){
app.get('/',function (req,res){
res.send('傳回')
})
}
7.對檔案資料查詢
核心代碼
var students = JSON.parse(data).students;
var stu=students.find(function (item){
return item.name===students[0].name;
})
//傳回name值與students[0].name一樣的資料
8.node操作資料庫
8.1 MongoDB
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/test');
var UserSchema=new mongoose.Schema({
UserName: String,
UserPwd: String,
UserEmail: String
})
const User = mongoose.model('User', UserSchema);
var Wu = new User({
UserName: 'Handsome Wu',
UserPwd: '123456',
UserEmail: '[email protected]'
});
/**
*增
*/
Wu.save(function (err,ret){
if(err){
console.log('failed:',err)
}else{
console.log(ret)
}
})
/**
*删
*/
User.remove({
UserName:'Handsome Wu'
},function (err,ret){
if(err){
console.log('failed:',err)
}else{
console.log(ret)
}
})
/**
*改
*/
User.findOneAndUpdate({
UserName:'Handsome Wu'
},{
UserPwd:'654321'
},function (err,ret){
if(err){
console.log('failed:',err)
}else{
console.log(ret)
}
})
/**
*查
*/
User.find({
UserName:'Handsome Wu'
},function (err,ret){
if(err){
console.log('failed:',err)
}else{
console.log(ret)
}
})
8.2 mysql
var mysql = require('mysql');
var connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'root',
database: 'test'
});
connection.connect();
//直接在這寫sql語句即可
connection.query('INSERT INTO `users` VALUES(null,"Beauty Wu","250250")', function (error, results, fields) {
if (error) throw error;
console.log('The solution is: ', results);
});
connection.end();
9. Promise
9.1 promise是用來解決 callback hell
的
callback hell
callback hell 本人了解是指因為js是異步程式設計,代碼不一定會按照寫的順序來執行,輸出具有不确定性,是以很多時候需要把另一個異步的函數放在另一個函數中,層層嵌套,
導緻代碼會非常難看
但我本人認為其實還挺好看的,另一個是難以維護,是以需要把層層嵌套改成單線程的形式
9.2.1 promise用法:
promise是JS自帶的一個api,無需引包!!!!!!!!!!!!!!!
我也不太懂,大概知道解決啥問題然後能依葫蘆畫瓢就行
var fs = require('fs')
var p1 = new Promise(function (resolve, reject) {
fs.readFile('./a.txt', function (err, data) {
if (err) {
reject(err)
} else {
resolve(data.toString())
}
})
})
var p2 = new Promise(function (resolve, reject) {
fs.readFile('./b.txt', function (err, data) {
if (err) {
reject(err)
} else {
resolve(data.toString())
}
})
})
//return的東西是下一個then的data
p1
.then(function (data) {
console.log(data)
return p2;
}, function (err) {
console.log('failed:', err)
})
.then(function (data) {
console.log(data)
})
9.2.2 promise封裝readFile
var fs = require('fs')
function pReadFile(filePath) {
return new Promise(function (resolve, reject) {
fs.readFile(filePath, function (err, data) {
if (err) {
reject(err)
} else {
resolve(data.toString())
}
})
})
}
pReadFile('./a.txt')
.then(function (data) {
console.log(data)
return pReadFile('./b.txt')
}, function (err) {
console.log(err)
})
.then((function (data) {
console.log(data)
}))
10. 檔案路徑問題
在node中執行檔案,在哪執行就認為被執行檔案在哪,這樣會導緻例如readFile時,如果讀取的路徑是相對路徑,那麼此時被require的檔案認為所處的目錄是運作檔案的目錄,進而導緻相對路徑不正确,具體問題見下圖
注意以上說法對require子產品不适用
檔案存儲如圖
//test.js
require('./test/test')
//test1.js
var fs=require('fs')
fs.readFile('./a.txt',function (err,data){
if(err){
console.log(err)
}else{
console.log(data)
}
})
以上代碼直接報錯
解決方法:用絕對路徑
此時需要用到node自帶的
__filename
&
__dirname
(兩個下劃線)
__filename
&
__dirname
這兩個不受上面所說的在哪執行就認為在哪限制
__filename
傳回檔案所處絕對路徑
__dirname
傳回檔案所處目錄的絕對路徑
具體代碼如下
var fs=require('fs')
var path=require('path')
fs.readFile(path.join(__dirname,'/a.txt'),function (err,data){
if(err){
console.log(err)
}else{
console.log(data)
}
})
11 題外話
11.1使用者密碼加密
md5加密,用法就是安裝然後引包使用即可
md5(password)
之後就會自動加密了,但是記得加密後的密碼在驗證時需要先把密碼加密再比對