expressでのルートと中間部品
46722 ワード
expressはnodejsのhttpモジュールパッケージに基づくフレームです。
以下は極めて簡単な用例である。
ルーティングパラメータの処理について
以下は極めて簡単な用例である。
const express = require("express");
const app = express();
app.param('userid', function(req, res, next, userid) {
req.user = getUser(userid);
next();
});
app.use("/water",function(req,res,next){
console.log("middle");
next();
});
function getUser(userId){
return {
userId,
age:8,
name:"freemen"
}
}
function setUser(user){
}
app.get('/username/:userid/:name',function(req,res){
console.log(req.user);
console.log(req.params);
req.user.name = req.params.name;
setUser(req.user);
res.end("update username success!");
});
app.get('/username/:userid/:age',function(req,res){
req.user.age = req.params.age;
setUser(req.user);
res.end("update username success!");
});
app.get("/user",function(req,res){
console.log(req.query);
console.log(req.path);
console.log(req.hostname);
});
app.listen(8888);
これらの機能を実装してみます。主にルートとミドルパーツです。
http Server関数をエクスポートしてこの関数にlistenという属性を定義します。彼がやるべきことは呼び出し時にhttpを使ってサービスを開始し、対応するポートを傍受します。 app.listen = (...rest)=>{
const server = http.createServer(app);
server.listen(...rest);
}
ルーティングと中間部品は同じキューに配置され、
でループバック関数が実行される。ルートと中間部品の違いは、中間部品が反復の権利すなわちnext関数を得て、そしてこのnext関数がエラー値を伝えた時にこのエラー値をクリアします。ルーティングパラメータの処理について
app.param('userid', function(req, res, next, userid) {
req.user = getUser(userid);
next();
});
まず、このような処理パラメータが必要な場合と普通のルーティングの唯一の違いを分析すると、ルーティングのアドレスに違いがある/username/:userid/:name
とは、:
の後の値を処理する必要があるということです。定義するときに有用な値を保存します。http.METHODS.forEach( method => {
const methods = method.toLocaleLowerCase();
app[ methods ] = function(path,cb){
const layer = { methods, path, cb };
if(path.includes(":")){
let paramsNames = [];
path = path.replace(/:([^\/]+)/g,function(){
paramsNames.push(arguments[1]);
return '([^\/]+)'
})
layer.path = new RegExp(path);
layer.paramsNames = paramsNames;
}
app.routers.push(layer)
}
})
その後、オブジェクトを定義して、これらのparamのパラメータキーの名前をルートのパラメータキーとして保存します。app.paramhandlers = {};
app.param = function(name,handler){
app.paramhandlers[name] = handler;
}
その後、反復時に、対応する判定ロジックを追加して、前に保存したパラメータを取り出し、対応する値を送る。if(route.paramsNames){
let machers = pathname.match(path);
if(machers){
let params = {};
for(let i=0; i < route.paramsNames.length;i++){
params[route.paramsNames[i]] = machers[i+1];
}
req.params = params;
for(let j=0;j<route.paramsNames.length;j++){
let name = route.paramsNames[j];
let handle = app.paramhandlers[route.paramsNames[j]];
if(handle){
return handle(req,res,()=>route.cb(req,res),req.params[name]);
}
}
}else{
next();
}
}
完全に次の通り実現しますconst http = require("http");
const url = require("url");
// listen use param app
function httpServer(){
const app = (req,res)=>{
const { pathname } = url.parse(req.url,true);
let index = 0;
function next(err){
if(index >= app.routers.length){
return res.end(`cannot find ${req.method}---${pathname}`);
}
let route = app.routers[index++];
const { methods ,cb ,path} = route;
if(err){
if( methods == "middle" ){
if(path=='/'||pathname.startsWith(path+"/")||path==pathname){
if(cb.length==4){
cb(err,req,res,next);
}else{
next(err);
}
}
}else{
next(err);
}
}else{
if( methods=="middle" ){
cb(req,res,next);
}else{
if(route.paramsNames){
let machers = pathname.match(path);
if(machers){
let params = {};
for(let i=0; i < route.paramsNames.length;i++){
params[route.paramsNames[i]] = machers[i+1];
}
req.params = params;
for(let j=0;j<route.paramsNames.length;j++){
let name = route.paramsNames[j];
let handle = app.paramhandlers[route.paramsNames[j]];
if(handle){
return handle(req,res,()=>route.cb(req,res),req.params[name]);
}
}
}else{
next();
}
}
if((route["path"] == pathname||route["path"]=="*")&&(req.method.toLocaleLowerCase() == route["methods"]|| route['methods']== "all" )){
return cb(req,res);
}else{
next();
}
}
}
}
next();
}
app.paramhandlers = {};
app.param = function(name,handler){
app.paramhandlers[name] = handler;
}
app.routers = [];
app.listen = (...rest)=>{
const server = http.createServer(app);
server.listen(...rest);
}
http.METHODS.forEach( method => {
const methods = method.toLocaleLowerCase();
app[ methods ] = function(path,cb){
const layer = { methods, path, cb };
if(path.includes(":")){
let paramsNames = [];
path = path.replace(/:([^\/]+)/g,function(){
paramsNames.push(arguments[1]);
return '([^\/]+)'
})
layer.path = new RegExp(path);
layer.paramsNames = paramsNames;
}
app.routers.push(layer)
}
})
app.all = function(path,cb){
app.routers.push({
methods:"all",
path,
cb
})
}
app.use = function(path,cb){
if(typeof cb !=="function"){
let middle = path;
cb = middle;
path = '/';
}
app.routers.push({
methods:"middle",
path,
cb
})
}
//
app.use(function(req,res,next){
const urlObj = url.parse(req.url,true);
req.query = urlObj.query;
req.path = urlObj.pathname;
req.hostname = req.headers['host'].split(":")[0];
next();
})
return app;
}
module.exports = httpServer;