【 Express 】 원본 읽 기 기록 (1)

9909 단어
비록 현재 사용자 express 가 간단 한 정적 서버 를 구축 하고 간단 한 데이터 상호작용 을 할 수 있 지만 그 이 유 를 모 르 는 느낌 이 듭 니 다.nodejs 에 대한 자체 적 인 이해 도 부족 합 니 다.마침 다음 소스 코드 를 읽 는 데 시간 이 좀 걸 렸 습 니 다. 본 고 는 Express 4.15.4 를 바탕 으로 합 니 다.
Express 주요 디 렉 터 리 구조
프로젝트 디 렉 터 리 구 조 는 가장 중요 한 부분 을 선택 하여 열 거 했 습 니 다.

├── lib
|   ├── middleware        
|   |   ├── init.js
|   |   └── query.js
├── ├── router        //router  ,             
|   |   ├── index.js
|   |   ├── layer.js
|   |   └── route.js
├── ├── application.js
├── ├── express.js
├── ├── request.js   //         request     
├── ├── reponse.js
├── ├── util.js
├── └── view.js      //           ,   res.render()         
|
└── index.js

express 와 app
express 에서 가장 많이 나타 나 는 것 은 express 으로 그 중요성 을 알 수 있다.예 를 들 어 가장 간단 한 정적 서버 를 구축 합 니 다.
const express = require('express')
const app = express()

app.get('/',function(req,res){
    res.send('Hello World!')
    res.end()
})
app.listen(3000,function(){
    console.log('      ...')
})

다음은 소스 코드 에서 express 와 app 을 분석 합 니 다.
/*
 * express.js
 */
//  express()   app       
exports = module.exports = createApplication
//createApplication    express  main   ,         express        
function createApplication(){
    var app = function(req,res,next){
        app.handle(req,res,next)
    }
    
    //     mixin  
    mixin(app,EventEmitter.protprype,false)
    mixin(app,proto,false)
    
    app.request = Object.create(req,{...})x
    app.response = Object.create(res,{...})
    
    return app
}

상기 코드 의 app. handle, handle 방법 은 application. js 에서 정의 합 니 다.우선 application. js 의 전체적인 구 조 를 살 펴 보 겠 습 니 다.
//application.js
app.init = function init(){
    this.cache = {}
    this.engines = {}
    this.settings = {}
    
    this.defaultConfiguration()
}

//app.    

app.render = function render(name,options,callback){...}  

app.listen = function listen(){
  var server = http.createServer(this);
  return server.listen.apply(server, arguments);
}  

//    
function logederror(err){...}
function tryRender(view,options,callback){...}

app 은 http. createServer 의 인자 로 요청 처리 함수 입 니 다.한편, express 는 공장 함수 로 요청 처리 함 수 를 생 성 하 는 데 사용 된다.왜 express 가 공장 함수 라 고 말 합 니까?정적 서버 를 구축 할 때의 코드 를 증명 할 수 있 습 니 다.
const app = express()

다음은 app. handle () 을 따로 제시 하여 연 구 를 해 보 겠 습 니 다. express. js 에서 mixin 을 통 해 가 져 왔 습 니 다.그 역할 은 각각 [req, res] 를 단계별 로 나 누 어 주 는 것 으로 정 의 된 경로 와 미들웨어 에 작용 하여 마지막 에 완성 하 는 것 이다.
app.handle = function(req,res,callback){
    var router = this._router
    
    //final handler
    var done = callback||finalhandler(req,res,{
        env:this.get('env'),
        onerror:logerror.bind(this)
    })
    
    //no routes
    if(!router){
        debug('no routes defined on app')
        done()
        return
    }
    router.handle(req,res,done)
}

여기 서 두 가지 관건 app 을 제외 하고
미들웨어
express 에서 가장 관건 적 인 개념 은 중간 부품 이다.하나의 Express 응용 은 본질 적 으로 일련의 미들웨어 호출 이다.그렇다면 도대체 중간 부품 은 무엇 입 니까?
하나의 중간 부품 은 본질 적 으로 하나의 함수 이 고, 중간 부품 을 호출 하 는 것 은 함수 에 대한 호출 이다.Express 4. x 에서 내 장 된 모든 미들웨어 를 취소 하고 외부 에서 도입 해 야 합 니 다.이러한 개선 은 express 는 독립 된 경로 와 웹 미들웨어 프레임 워 크 로 업데이트 가 더욱 편리 하고 유 닉 스 철학 에 더욱 부합된다.
미들웨어 일반 함수 형식 은 다음 과 같다.
function middleware(req,res,next){
    //...
}

이상 처 리 는 비동기 프로 그래 밍 의 어 려 운 점 입 니 다. 우 리 는 일반적인 구문 블록 으로 이상 을 포착 할 수 없습니다.try - catch 는 이번 이벤트 순환 내 이상 만 포착 할 수 있 으 며, callback 실행 에 던 진 이상 은 어 쩔 수 없습니다.따라서 Node 는 처리 이상 에 있어 서 일종 의 약속 을 형성 하여 이상 을 리 셋 함수 의 첫 번 째 실제 인삼 으로 전송 합 니 다. 빈 값 이 라면 처리 오류 미들웨어 함수 형식 을 이상 하 게 던 지지 않 았 음 을 나타 냅 니 다.
function middleware(err,req,res,next){
    //error     
    //...
}

다음은 미들웨어 함수 의 인 자 는 req 와 res 를 무시 합 니 다. try-catch 자체 도 하나의 함수 입 니 다. 호출 next 은 다음 미들웨어 를 계속 실행 합 니 다.요청 프로 세 스 도 해 는 다음 과 같 습 니 다.
       ↓
---------------
| middleware1 |
---------------
       ↓
---------------
| ... ... ... |
---------------
       ↓
---------------
| middlewareN |
---------------
       ↓

express 를 사용 할 때 우 리 는 이런 코드 를 자주 볼 수 있다.
//     /user     
app.use('/user',function(req,res,next){...})

//     /user  
app.get('/user',function(req,res,next){...})

상기 코드 에 따 르 면 중간 부품 은 크게 두 가지 로 나 눌 수 있다. next() .일반 미들웨어 등록 은 보통 을 통 해 이 루어 지고 등록 로 는 미들웨어 로 보통 app.use() 를 통 해 등록 된다.이 두 가지 방법 은 모두 app.METHOD() 에 의 해 처리 된다.
경로 라 우 터
요청 처리 의 상세 한 과정 을 알 고 싶다 면 우선 Router 를 알 아야 한다.우선 Routerde 디 렉 터 리 구 조 를 살 펴 보 겠 습 니 다.
├── router      
|   ├── index.js
|   ├── layer.js
|   └── route.js

쉽게 말 하면 Router (원본 코드 는 router / index. js) 는 중간 부품 의 용기 이다.사실 Router 는 Express 에서 매우 핵심 적 인 것 으로 기본적으로 간략화 된 Express 프레임 워 크 이다.app 의 많은 API, 예 를 들 어 app. use (), app. param (), app. handle () 등 은 사실상 Router API 에 대한 간단 한 포장 입 니 다.app.router 는 기본 Router 대상 에 접근 합 니 다.
app. get () 이 어떻게 이 루어 졌 는 지
methods.forEach(function(method){
    // JavaScript     '[]'   '.'       .
    //         ,              '[]'
    app[method] = function(path){
        if(method==='get' && arguments.length===1){
            //app.get(setting)
            return this.set(path)
        }
        this.lazyrouter()
        
        var route = this._router.route(path)
        route[method].apply(route,slice.call(arguments,1))
        return this
    }
})

상기 코드 를 통 해 우 리 는 Express 가 app.handle 방법 에 대한 추 가 는 모두 동태 적 인 것 이 라 고 보 낼 수 있다.하나의 foreach 순환 이 모든 method 함수 의 정 의 를 해 결 했 습 니 다.함수 의 내부 구현 을 보 세 요. 함수 매개 변수 길이 가 1 이면 this. set (path) 로 바로 돌아 갑 니 다.Express API 를 보면 알 수 있 듯 이 METHOD 두 가지 기능 을 실 현 했 습 니 다. 길이 가 1 이면 app. set () 가 정의 한 변 수 를 되 돌려 주 고 매개 변수 길이 가 1 보다 크 면 경로 처 리 를 합 니 다.
이 어 app.get() 소스 코드 로 포 지 셔 닝
app.lazyrouter = function lazyrouter(){
    if(!this._router){    //  _router   , new  Router  
        this._router = new Router({
            caseSensitive: this.enabled('case sensitive routing'),
            strict: this.enabled('strict routing')
        })
        this._router.use(query(this.get('query parse fn')))
        this._router.use(middleware.init(this))
    }
}

이 new 에서 나 온 Router 는 본질 적 으로 중간 부품 용기 이다.그리고 this.lazyrouter().app 의 많은 API, 예 를 들 어 app. use (), app. param (), app. handle () 등 은 사실상 Router API 에 대한 간단 한 포장 입 니 다.app.router 는 기본 Router 대상 에 접근 합 니 다.
이전 Router Express , Express 으로 돌아 가면 this. lazyrouter () 를 실행 한 후에 methods.forEach 는 경로 처리 함 수 를 저장 하 는 용기 로 간단하게 이해 할 수 있 습 니 다. 하나의 Route 속성 은 하나의 배열 이 고 그 중의 모든 항목 은 Layer 대상 이 며 경로 처리 함수 에 대한 포장 입 니 다.
var route = this._router.route(path)

상기 코드 에 따라 찾 을 수 있 습 니 다 stack
proto.route = function route(path){
    var route = new Route(path)
    
    var layer = new Layer(path,{
        sensitive:this.caseSensitive,
        strict:this.strict,
        end:true
    },route.dispatch.bind(route))
    
    layer.route = route
    
    this.stack.push(layer)
    return route
}

여기 new 는 하나의 router/index.js 대상 과 하나의 route 대상 을 만 든 다음 에 route 대상 을 layer. route 에 할당 합 니 다.
Route 모듈 에 대응 하 는 것 은 route. js 입 니 다. 주로 경로 정 보 를 처리 하 는 것 입 니 다. 모든 경로 에서 Route 인 스 턴 스 를 생 성 합 니 다.한편, Router 모듈 은 index. js 에 대응 하고 Router 는 하나의 경로 의 집합 으로 Router 모듈 에서 여러 개의 경 로 를 정의 할 수 있 습 니 다. 즉, 하나의 Router 모듈 은 여러 개의 Route 모듈 을 포함 합 니 다.위의 코드 를 통 해 우 리 는 모든 express 가 만 든 인 스 턴 스 가 하 나 를 게 으 르 게 불 러 올 것 이라는 것 을 이미 알 고 있 습 니 다.router 가 경로 처 리 를 합 니 다. 이router 는 Router 모듈 입 니 다.
그렇다면 layer 경 로 를 어떻게 구체 적 으로 처리 하 는 지
methods.forEach(function(method){
  Route.prototype[method] = function(){
    var handles = flatten(slice.call(arguments));

    for (var i = 0; i < handles.length; i++) {
      var handle = handles[i];

      if (typeof handle !== 'function') {
        var type = toString.call(handle);
        var msg = 'Route.' + method + '() requires callback functions but got a ' + type;
        throw new Error(msg);
      }

      debug('%s %o', method, this.path)

      var layer = Layer('/', {}, handle);
      layer.method = method;

      this.methods[method] = true;
      this.stack.push(layer);
    }

    return this;
  };
});

application. js 에서 처리 하 는 방식 과 같 습 니 다.호출 route 할 때 새 layer 를 route.MEHOD() 에 놓 습 니 다.
위의 분석 을 통 해 Router 는 사실 2 차원 구조 임 을 알 수 있다.예 를 들 어 가능 한 router. stack 구 조 는 다음 과 같다.
----------------
|    layer1    |
----------------
        ↓
---------------- layer2.route.stack  ------------   ------------   ------------
|    layer2    | ------------------> | layer2-1 |-->| layer2-2 |-->| layer2-3 |
----------------                     ------------   ------------   ------------
        ↓
---------------- layer3.route.stack  ------------   ------------
|    layer3    | ------------------> | layer3-1 |-->| layer3-2 |
----------------                     ------------   ------------
        ↓
----------------
|    ......    |
----------------
        ↓
----------------
|    layerN    |
----------------
route.stack , :app.METHOD-->router.route-->route.METHOD
기타 참조 링크
원본 주소
Express 4.15.4
참조 링크 4
  • 프론트 스 튜
  • express 소스 코드 에서 그 경로 체 제 를 분석
  • EXPRESS 4. X 소스 코드 해독
  • 박 영
  • express 소스 코드 분석의 Router
  • 좋은 웹페이지 즐겨찾기