詳解express搭建http服務,通過路由和中間件獲取靜態文件和動態數據的實現原理


express方法

Express是一個簡潔、靈活的node.js Web應用開發框架,是目前最流行的基於Node.js的Web開發框架. 它提供一系列強大的功能,比如:

*模板解析
*靜態文件服務
*中間件
*路由控制

在node中使用express創建一個http請求,具體步驟如下:
1,引入express模塊
2,執行express方法
3,express方法執行后返回一個http的監聽函數,可以用返回的函數監聽端口

通過使用中間件請求靜態資源

express搭建服務

let express=require("express");
let app=express();
app.listen(8080);

express函數執行后,返回的是一個http的監聽函數,就是http.createServer中的函數
在此函數上擴展了一個listen可以監聽端口,app.listen就是基於以前封裝的

app.listen=function (...arg) {
    require("http").createServer(app).listen(...arg)
}
app.listen(8080,()=>{
	"8080端口已開啟"
})

基於express的監聽函數app上擴展了很多的方法

express路由

必須method和path全都匹配上執行對應的callback
1.在處理請求路徑和方式上,指明了請求的方式,包括get post delete put,RESTful風格中的動詞,與之前相比不需在進行判斷了

app.get("/sigin",function (req,res) {
    res.setHeader("content-type","text/plain;charset=utf-8");
    res.end("登錄");
});
app.post("/sigin",function (req,res) {
    res.setHeader("content-type","text/plain;charset=utf-8");
    res.end("post登錄");
});
//all表示所有的方法,*表示所有的路徑,一般放到最后
app.all("*",function (req,res) {
    res.end("404")
})

若請求localhost:8080/sigin,則返回登錄

參數路由:

在路徑中針對同一路徑,我們可以通過路由參數,區分查一個或者多個內容,所有的路由參數都放到req.params對象中,

app.get("/user",function (req,res) {
    res.end("select all")
});
app.get("/user/:id/:name",function (req,res) {
    res.end("select one"+req.params.id+req.params.name);
});

2.如果想拿到請求的路徑參數可以使用app.params()方法拿到,此方法具有攔截功能,只有調用了next()方法后才繼續往下走

app.param("id",function (req,res,next) {
    req.params.id=`你的學號是${req.params.id}`;
    //res.end("123")
     next();//調用了next就可以向下匹配,如果在這里結束了請求那就不走了

});
app.param("name",function (req,res,next) {
    req.params.name=`你的名字是${req.params.name}`;
    next();

})
app.get("/user/:id/:name",function (req,res) {
    res.header("content-type","text/plain;charset=utf-8");
    res.end("select one"+req.params.id+req.params.name);
});

響應成功返回內容:select one你的學號是1你的名字是md

中間鍵

訪問到最終目標之前做一些事情,那么app.use()方法就可以
app.use()
1)功能

1.可以進行權限判斷
2.可以對res和req的屬性進行擴充
3中間鍵放在要執行的路徑上面
4中間鍵默認情況下都匹配,可以指定匹配什么開頭

2) 使用
在匹配路由,返回數據之前,如果我們想做一些事情,也可以使用中間件

 app.use(function (req,res,next) {//不調用next就不繼續往下走
    console.log("過濾石頭");
    req.stone="too big";
    res.end("hello");
    next();
    // next("錯誤");
});
app.use(function (req,res,next) {//不調用next就不繼續往下走
    console.log("過濾沙子");
    req.sand="too small";
 next();
});
app.get("/foot",function (req,res) {
    console.log(req.stone,req.sand);
    res.end("foot");

})
app.get("/water",function (req,res) {
    console.log(req.stone,req.sand);
    res.end("water");

});
app.use(function (err,req,res,next) {
    console.log(err);
    next();
})

如果next()里面傳了參數,中間鍵走擁有四個參數的方法,即最后的方法
3)方法封裝原理

function app() {
    //每次調用use方法都會將方法存到數組中,默認調用數組的第一項,將next方法傳遞給數組中的函數,如果調用次函數  會繼續執行數組中的下一項
    app.middlereware=[];

}
app.use=function (cb) {
    this.middlereware.push(cb);
};
app.use(function (res,req,next) {
    console.log(1);
    next();
});
app.use(function (res,req,next) {
    console.log(2);
    next();
});
app.use(function (res,req,next) {
    console.log(3);
});
let index=0;
function next() {
    app.middlereware[index++](null,null,next);
};
next();

擴展了res,req里的一些屬性和方法

1)req上擴展的屬性和方法
req.query.id 獲取路由參數
req.path 獲取路徑

let express=require("express");
let app=express();
app.listen(8081);
app.get("/user",function (req,res) {
    console.log(req.query.id);//express擴展的屬性
    console.log(req.url);//獲取整個路徑包括問號
    console.log(req.path);//express擴展的屬性
    console.log(req.headers);//所有的都是小寫
    console.log(req.method);//所有的方法都是大寫
})

2)res上擴展的屬性和方法
1,res,json(),直接返回json格式的字符串返回
以前響應返回的數據需要通過JSON.stringFly()轉化之后才能返回

app.get("/json",function (req,res) {
    res.json({name:"你好",age:8});//響應json
});

2,以前返回一個頁面文件需要通過fs讀取,現在可以通過res.sendFile()方法拿到,路徑必須是絕對路徑

app.get("/",function (req,res) {
    // res.sendFile("./index.html",{root:__dirname});不能通過../查找(root是不支持的)想讀取到確切的文件 用path模塊進行拼接即可
    res.sendFile(require("path").join(__dirname,"..","index.html"))
});

3.返回狀態碼無需通過res.setStateCode(),可以使用res.send(),也可以返回中文,無需設置響應頭的類型,可以根據返回的數據類型,自動設置返回的響應頭類型

app.get("/send",function (req,res) {
    // res.send("中文")
    res.send(200)
});

send()方法的封裝

app.use(function (req,res,next) {
    res.mySend = function (data) {
        if(typeof data === 'object'){
            res.setHeader('Content-Type','application/json;charset=utf8');
            return res.end(JSON.stringify(data));
        }
        if(typeof data === 'string'){
            res.setHeader('Content-Type','text/plain;charset=utf8');
            return res.end(data);
        }
        if(typeof data === 'number'){
            res.statusCode = data;
            res.end(require('_http_server').STATUS_CODES[data]);
        }
    };
    next();
});
app.get('/send',function (req,res) {
    res.mySend(500);
}

路由拆分(設置二級路由)獲取動態數據

可以通過express上可以通過express.Router()和中間件設置子級路由把所有的子路由都放在一個routes文件夾下,該文件夾下可以放置多個相同的模塊,每個模塊中都需要引入express模塊,設置子路由的路徑和相應的方法,並將該模塊導出moudle.export={},然后在主模塊中引用routes文件夾子模塊,通過require,然后通過中間件use()方法,匹配二級路由

let express = require('express');
let app = express();
let router = express.Router();
router.get('/login',fn)
app.use('/user',router);

bodyParser

app.use(bodyParser.json()); // 解析json application/json
app.use(bodyParser.urlencoded({extented:true})); // 解析表單 application/x-www-form-urlencoded
  • ejs用法
<!--引入模板-->
<%include header.html%>
<!--取值-->
<h1><%=username%></h1>
<p><%=password%></p>
<!--js語句-->
<%arr.forEach(item=>{%>
    <li><%=item%></li>
<%})%>
<!--轉譯-->
<%-html%>

ejs模板渲染的文件默認是帶有ejs后綴的文件,並且是放在當前目錄下的view文件夾,並且在拿到數據后想要通過render函數渲染數據的話,渲染的模板文件是帶有ejs后綴的,可以通過中間件把模板文件的后綴更改成html,view文件夾的名字更改為static文件

//更改默認模板的后綴
app.engine('html',require('ejs').__express);
// 更改模板路徑,默認叫views
app.set('views','static');
// 配置默認模板后綴名字
app.set('view engine','html');

靜態服務中間件

通過express.static()請求文件文件

app.use(express.static('文件夾'))

重定向

res.redirect('路徑');

由此我們就可以基於express方法搭建一個http,服務,通過express.Router(),搭建子級路由,獲取和響應數據,通過express.static()方法可以請求靜態資源,通過app.use()中間,對請求的路由,數據,響應的數據進行再處理,從而提高了整個hhtp請求的可控性


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM