2020-2-20-nodejs基礎知識

SylvesterZhang發表於2024-03-22

vs外掛安裝、快速執行、url模組使用、自動重啟工具supervisor、自定義模組、下載第三方包、fs模組、Async、Await的使用、檔案裡、簡易靜態伺服器、事件驅動EventEmitter、模擬登陸簡單版、模擬express封裝、操作mongodb資料庫

VScode外掛安裝

需要安裝Node Snippets外掛才會有提示


快速執行

var http=require('http')
http.createServer((req,res)=>{
    //req 請求物件,可獲取請求的url等資訊
    //res 響應物件
    console.log(req.url)
    res.writeHead(200,{"Content-type":"text/html;charset='utf-8"})
    res.write("<head><meta charset='UTF-8'></head>")//解決亂碼
    res.write("你好,hello")//向前臺返回內容
    res.end()//結束響應,註釋掉前臺將會一直請求
}).listen(3000)

url模組的使用

//對於get方式傳值好用
const url=require('url')
let api="www.zhanghuan.top?name=zhanghuan&age=20"
let parse_reasult=url.parse(api,true).query
console.log(parse_reasult)//[Object: null prototype] { name: 'zhanghuan', age: '20' }

自動重啟動工具supervisor

1)安裝

npm install -g supervisor

2)使用supervisor代替node命令啟動應用

supervisor server.js

自定義模組

新建一個資料夾module,裡面放置js檔案,一個js檔案就是一個自定義模組,例如在module裡新建request.js檔案

1)建立模組

//request.js裡的程式碼
class request{
    static get(){
        console.log("get方法")
    }
    static post(){
        console.log("post方法")
    }
}
//對外暴露寫法1,選擇性暴露
//exports.request=request

//對外暴露寫法2,將整個物件暴露
module.exports=request

2)匯入模組

//在modules外部app.js中
var req=require('./modules/request')
req.get()//輸出 get方法

3)node_modules系統方式自定義模組

新建一個node_modules的資料夾,裡面建一個axios資料夾,裡面新建一個index.js的檔案,那麼在外部(與node_modules同級的js檔案中)可直接使用require('./axios')匯入檔案

注意:如果axios裡的js檔案命名不是index.js,用這種方法匯入會報錯。解決辦法是,在axios檔案裡開啟命令視窗,輸入npm init --yes


下載第三方包

1初始化

npm init --yes

生成配置檔案package.json,package-lock.json

2安裝包

例如我們要安裝MD5的包

npm install --save

注意:這裡的--save會將安裝的包名記錄到配置檔案中,別人拿到配置檔案後執行命令npm install便可安裝所有依賴

指定包的版本安裝

npm install jquery@1.8.0

3常見的包

silly-datetime(日期格式化)

mkdirp(建立檔案)

4刪除模組

1)簡單方法

npm uninstall md5

2)另一種方法

在package.json中的dependencies屬性下,刪除掉該模組,然後刪除掉node_modules資料夾,再重新執行npm install

5配置檔案裡dependencies屬性裡的表示符

"dependencies": {
    "md5": "^2.2.1"
  }

^表示第一位版本號不變,後面兩位取最新

~表示前兩位不變,最後一個取最新

*表示全部取最新


fs模組

1fs.stat('dir',callback)判斷路徑是否存在

fs.stat(path,(err,data)=>{
    if(err){
        console.log(err)
    }else{
        //data是一個名為status的物件,這個物件有isDirectory()和isFile()方法,呼叫以檢視該路徑是否是檔案
        console.log(data.isDirectory())
        console.log(data.isFile())
    }
})

2fs.mkdir('dir',callback)建立路徑

3fs.writeFile('dir','file.content',callback)新建檔案

4fs.appendFile('dir','append content',callback)檔案追加內容

5fs.readFile('dir',callback)

6fs.readDire('dir',callback)閱讀目錄下包含的所有檔案和資料夾

7fs.rename('dir','new dir',callback)重新命名或移動檔案

8fs.rmdir('dir',callback)刪除路徑,前提是路徑下不包含任何檔案和資料夾

9fs.unlin('dir',callback)刪除路徑下的檔案

例子:使用回撥函式取出目標路徑下所有檔案的檔名

const fs=require('fs')
var dir='../../../desktop'//查詢的地址
var lis=[]//查詢到的檔案放置在這裡
function get_filename(dir){
    fs.readdir(dir,(err,data)=>{
        if(err){
            console.log(err)
            return
        }else{
            if(data==[]){
                return
            }
            (function getdir(i){
                if(i==data.length){
                    return
                }
                var path=dir+'/'+data[i]
               fs.stat(path,(err,status)=>{
                    if(status.isFile()){//如果傳過來的是檔案,新增到lis中
                        lis.push(path)
                    }else{//如果傳過來的是路徑,進行遞迴
                        get_filename(path)
                    }
               })
                getdir(i+1)
            })(0)
            //這裡不可以用for迴圈迭代,因為fs是非同步的,用遞迴方式替代for迴圈
        }
    })
}
get_filename(dir)
var t=setInterval(()=>{
    console.log(lis)//因為fs是非同步的,所以會執行更長時間,這裡等待3秒後輸出結果
    clearInterval(t)
},3000)

Async、Await的使用

async是宣告一個非同步的function,await是等待一個非同步function的執行完成並獲取非同步function返回的資料,注意await外部包裹的方法必須是非同步方法(擴充套件:所有返回為Promise的函式都可以用await獲取其resolve的值)

async function test(){
    return new Promise((resolve,reject)=>{
        t=setInterval(()=>{       
            clearInterval(t)
            resolve("你好")
        },3000)
    })
    
}

async function main(){
    var data=await test()//外部必須是非同步函式包裹
    console.log(data)//3秒後執行這一行,和下面這一行
    console.log("hello")
}
main()

取出目標路徑下所有檔案的檔名非同步版本

const fs=require('fs')
var dir='../../../desktop'//查詢的地址
var lis=[]//查詢到的檔案放置在這裡
async function dir_isFile(path){
    //@params path路徑
    //根據路徑判斷是否是檔案,如果是檔案返回真
    return new Promise((resolve,reject)=>{
        fs.stat(path,(err,status)=>{
            if(err){
                console.log(err)
            }
            resolve(status.isFile())
        })
    })
}
function get_filename(dir){
    fs.readdir(dir,async (err,data)=>{//函式內需要使用await,所以必須定義成非同步函式
        if(err){
            console.log(err)
            return
        }else{
            if(data==[]){
                return
            }
            for(var item of data){
                var path=dir+'/'+item
                if(await dir_isFile(path)){
                    lis.push(path)
                }else{
                    get_filename(path)
                }
            }
           
        }
    })

}

get_filename(dir)
var t=setInterval(()=>{
    console.log(lis)
    clearInterval(t)
},10000)   

檔案流

1讀取流

const fs=require('fs')
var readstream=fs.ReadStream('new_file','utf-8')
var num=0//記錄讀取次數
readstream.on('data',(data)=>{
    console.log(data)//輸出讀取的資料
    num++//每讀取一次加一
})
readstream.on('end',()=>{
    console.log("--end--")
    console.log(num)//輸出10,說明讀取了10次
})
readstream.on('error',(err)=>{
    console.log(err)//讀取過程中出現錯誤就輸出錯誤
})

2寫入流

const fs=require('fs')
var writestream=fs.WriteStream('new_file')
for(var i=0;i<10000;i++){
    writestream.write('閱讀使人充實,會談使人敏捷,寫作使人精確。\n')
}
writestream.end()//標記末尾,未標記末尾的檔案不可以觸發以下的完成事件
writestream.on('finish',()=>{
    console.log("寫入完成")
})

3管道流

const fs=require('fs')
var readstream=fs.ReadStream('new_file')
var writestream=fs.WriteStream('./files/new_file1')
readstream.pipe(writestream)//透過管道將new_file檔案複製到'./files/new_file'裡,注意複製前files資料夾必須存在

簡易靜態web伺服器

var http = require('http');
var fs=require('fs');
var url=require('url');
var path=require('path');

http.createServer(function (request, response) {
    var req_path=request.url;
    if(req_path!='/favicon.ico'){
        var pathname='.'+url.parse(req_path).pathname
        var ext_name=path.extname(pathname)//獲取字尾名
        fs.readFile(pathname,(err,data)=>{
            if(err){
                fs.readFile('./static/404.html',(err,data)=>{
                    response.writeHead(200, {'Content-Type': "text/html"});
                    response.write(data)
                    response.end();
                })
            }else{
                var head_obj=JSON.parse(fs.readFileSync('./static/mime.json').toString())//根據字尾名匹配出返回的請求頭
                if(ext_name in head_obj){
                    var content_type=head_obj[ext_name]
                }else{
                    var content_type='text/plain'
                }
                response.writeHead(200, {'Content-Type': content_type});
                response.write(data)
                response.end();
            }
        })
    }
  

  
}).listen(8081);

console.log('Server running at http://127.0.0.1:8081/');

事件驅動EventEmitter

var events=require('events');
var EventEmitter=new events.EventEmitter();

EventEmitter.on('data1',(data)=>{
    console.log(data)
})

EventEmitter.emit('data1',"this is data")//this is data

模擬登陸簡單版

1app.js檔案

var http = require('http');
var ejs=require('ejs');
var url=require('url');
var querystring=require('querystring')

http.createServer(function (request, response) {
    if(request.url!="/favicon.ico"){
        var pathname=url.parse(request.url).pathname
        if(pathname='/login'){
            if(request.method=='GET'){
                ejs.renderFile('./templates/login.ejs',{},(err,data)=>{
                    response.end(data)
                })
            }else{
                var posstr=""
                request.on('data',chunk=>{
                    posstr+=chunk
                })
                request.on('end',()=>{
                    var data_obj=querystring.parse(posstr)
                    response.writeHead(200,{'Content-Type': "text/html"})
                    if(data_obj['username']=='zhanghuan'&&data_obj['password']=='123'){
                        response.end("<script>alert('suceess');history.back()</script>")
                    }else{
                        response.end("<script>alert('username or password is not correct');history.back()</script>")
                    }
                    
                })
            }
            
        }
    }
  
}).listen(8081);

console.log('Server running at http://127.0.0.1:8081/');

2模板檔案login.ejs

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <p>login</p>
    <form action="/login" method="post">
        <input type="text" placeholder="使用者名稱" name="username">
        <input type="text" placeholder="密碼" name="password">
        <button>提交</button>
    </form>
    
</body>
</html>

模擬express的簡單封裝

1封裝檔案server.js程式碼

var url=require('url');
var server=function(){
    var G=this
    G._get={}
    G._post={}

    var app=function(req,res){
        var pathname=url.parse(req.url).pathname+'/'
        if(pathname=='/favicon.ico/'){
            return
        }
        if(!G._get[pathname]){//如果沒有定義該路由,直接返回
            res.end("no such router")
        }
        if(req.method=='GET'){
            try {
                G._get[pathname](req,res)//執行_get裡對應的方法
            } catch (error) {
                res.end("err")
            }
        }
        if(req.method=='POST'){
            try {
                var str=""
                req.on('data',(chunk)=>{
                    str+=chunk
                })
                req.on('end',()=>{
                    req.body=str
                    G._post[pathname](req,res)//執行_post裡對應的方法
                })
                
            } catch (error) {
                res.end("err")
            }
        }
    }

    app.get=function(string,callback){
        if(!string.startsWith('/')){
            string='/'+string
        }
        if(!string.endsWith('/')){
            string=string+'/'
        }
        if(string=='/'){
            string='//'
        }
        G._get[string]=callback
    }

    app.post=function(string,callback){
        if(!string.startsWith('/')){
            string='/'+string
        }
        if(!string.endsWith('/')){
            string=string+'/'
        }
        if(string=='/'){
            string='//'
        }
        G._post[string]=callback
    }

    return app
}

module.exports=server()

2檔案app.js

var http = require('http');
var app=require('./server.js');
var ejs=require('ejs');
var querystring=require('querystring')

http.createServer(app).listen(8081);

app.get('/',(req,res)=>{
    res.writeHead(301, {'Location': '/login'});//實現重定向
    res.end();
})

app.get('/login',(req,res)=>{
    ejs.renderFile('./templates/login.ejs',{},(err,data)=>{
        res.end(data)
    })
})
app.post('/login',(req,res)=>{
    var data_obj=querystring.parse(req.body)
    if(data_obj['username']=='zhanghuan'&&data_obj['password']=='123'){
        res.end("<script>alert('suceess');history.back()</script>")
    }else{
        res.end("<script>alert('username or password is not correct');history.back()</script>")
    }
})
console.log('Server running at http://127.0.0.1:8081/');


操作mongodb資料庫

1安裝模組

npm install mongodb --save-dev

2匯入模組並連線

var MongoClient=require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017',(err,client)=>{
     if(err){
         console.log(err)
     }
     var db=client.db("db01")//連線到db01資料庫
     //所有關於資料庫db01的操作都對db發起即可
     //db.collection('user')
     //拿到user表,可對其進行增刪改查操作
 })

3對錶格的操作

1)新增

var insert_obj={'name':'zhanghua','age':21]}
db.collection('user').insertOne(insert_obj,(err,data)=>{
	if(err){
		console.log(err)
	}
	res.end("insert success")
})

2)刪除

db.collection("user").deleteOne({'name':'zhanghuan'},(err,data)=>{
	if(err){
		console.log(err)
	}
	res.end("delete success")
})

3)修改

var update_obj={'name':'zhanghuan123'}
db.collection("user").updateOne({'name':'zhanghuan'},{$set:update_obj},(err,data)=>{
	if(err){
		console.log(err)
	}
	res.end("update success")
})

4)查詢

db.collection('user').find({}).toArray((err,result)=>{
	client.close()
	console.log(result)//拿到的結果會以陣列形式存在result裡         
})

4使用者列表增刪改查的案例

這裡是在模擬的express框架下進行操作

1)app.js檔案

var http = require('http');
var app=require('./server.js');
var ejs=require('ejs');
var querystring=require('querystring');
var url=require('url');
var querystring=require('querystring');
var MongoClient=require('mongodb').MongoClient;
var ObjectID = require('mongodb').ObjectID;
var db_url='mongodb://localhost:27017';

http.createServer(app).listen(8081);

//使用者列表
app.get('/user',(req,res)=>{
    MongoClient.connect(db_url,(err,client)=>{
        if(err){
            console.log(err)
            res.end('db error')
        }
        var db=client.db("db01")
        
        db.collection('user').find({}).toArray((err,result)=>{
            client.close()
            ejs.renderFile('./templates/content.ejs',{'list':result},(err,data)=>{
                if(err){
                    console.log(err)
                }
                res.end(data)
            })            
        })
        
    })
    
})

//刪除使用者
app.get('/userdel',(req,res)=>{
    MongoClient.connect(db_url,(err,client)=>{
        if(err){
            console.log(err)
            res.end('db error')
        }
        var db=client.db("db01")
        var _id=querystring.parse(url.parse(req.url).query)['id']
        _id=new ObjectID(_id)
        db.collection("user").deleteOne({'_id':_id},(err,data)=>{
            if(err){
                console.log(err)
                res.end('delete failure')
            }
            res.end("delete success")
        })
    })
})

//新增使用者
app.get('/adduser',(req,res)=>{
    ejs.renderFile('./templates/adduser.ejs',{'obj':''},(err,data)=>{
        res.end(data)
    })
})
app.post('/adduser',(req,res)=>{
    var data_obj=querystring.parse(req.body)
    MongoClient.connect(db_url,(err,client)=>{
        if(err){
            console.log(err)
            res.end('db error')
        }
        var db=client.db("db01")
        var insert_obj={'name':data_obj['name'],'age':data_obj['age'],'sex':data_obj['sex'],'job':data_obj['job']}
        db.collection('user').insertOne(insert_obj,(err,data)=>{
            if(err){
                console.log(err)
                res.end('insert failure')
            }
            res.end("insert success")
        })
    })
})

//更新使用者
app.get('/userupdate',(req,res)=>{
    MongoClient.connect(db_url,(err,client)=>{
        if(err){
            console.log(err)
            res.end('db error')
        }
        var db=client.db("db01")
        var _id=querystring.parse(url.parse(req.url).query)['id']
        _id=new ObjectID(_id)
        db.collection('user').find({'_id':_id}).toArray((err,result)=>{
            client.close()
            ejs.renderFile('./templates/adduser.ejs',{'obj':result[0],'current_url':req.url},(err,data)=>{
                if(err){
                    console.log(err)
                }
                res.end(data)
            })            
        })
        
    })
})
app.post('/userupdate',(req,res)=>{
    var data_obj=querystring.parse(req.body)
    MongoClient.connect(db_url,(err,client)=>{
        if(err){
            console.log(err)
            res.end('db error')
        }
        var db=client.db("db01")
        var _id=querystring.parse(url.parse(req.url).query)['id']
        _id=new ObjectID(_id)
        var update_obj={'name':data_obj['name'],'age':data_obj['age'],'sex':data_obj['sex'],'job':data_obj['job']}
        db.collection("user").updateOne({'_id':_id},{$set:update_obj},(err,data)=>{
            if(err){
                console.log(err)
                res.end('update failure')
            }
            res.end("update success")
        })
    })
})

console.log('Server running at http://127.0.0.1:8081/');

2)adduser.ejs

{% raw %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>add or update</title>
</head>
<body>
    <%if(obj){%>
        <form action=<%=current_url%> method="post">
            <input type="text" name='name' placeholder="name" required value=<%=obj.name%>>
            <input type="text" name='age' placeholder="age" required value=<%=obj.age%>>
            <input type="text" name='sex' placeholder="sex" required value=<%=obj.sex%>>
            <input type="text" name='job' placeholder="job" required value=<%=obj.job%>>
            <button>提交</button>
        </form>
    <%}%>
    <%if(!obj){%>
        <form action="/adduser" method="post">
            <input type="text" name='name' placeholder="name" required>
            <input type="text" name='age' placeholder="age" required>
            <input type="text" name='sex' placeholder="sex" required>
            <input type="text" name='job' placeholder="job" required>
            <button>提交</button>
        </form>
   <% }%>
    
</body>
</html>
{% endraw %}

3)content.ejs

{% raw %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>userlist</h1>
    <table>
        <tr>
            <th>name</th>
            <th>age</th>
            <th>sex</th>
            <th>job</th>
            <th>operation</th>
        </tr>
        <%for(item of list){%>
            <tr>
                <td><%=item.name%></td>
                <td><%=item.age%></td>
                <td><%=item.sex%></td>
                <td><%=item.job%></td>
                <td><a href="userdel?id=<%=item._id%>">刪除</a><a href="userupdate?id=<%=item._id%>">更新</a></td>
            </tr>
        <%}%>
    </table>
    <br>
    <button><a href="/adduser">新增使用者</a></button>
</body>
</html>
{% endraw %}