What is the NodeJS middle tier?

Is front end – request – > nodejs request — — — — – > the back-end response — — — – > nodejs – data processing response — — — — — — — > the front end. Such a process, the advantage of this process is that when the business logic is too much, or the business requirements are constantly changing, the front end does not need to change the business logic as much, low coupling to the back end. The front end is display and render. The backend retrieves and stores data. The middle layer processes the data structures and returns them to the front end as renderable data structures.

Nodejs plays the role of the middle layer, that is, to do the corresponding processing or rendering of the page according to the different requests of the client. During the processing, the data can be simply processed by the underlying Java side for real data persistence or data update, or it can be retrieved from the underlying data for simple processing and returned to the client.

Project Construction:

1. Technology selection: I chose express framework to develop the middle layer.

2.$NPM install Express –save

3.$NPM install express-generator-g Use the Express generator to generate a completed project structure.

3.$NPM install pm2 -g

$pm2 start Express project name /bin/ WWW –watch Express project, and listen for some file changes, once the code changes, automatically restart nodeJS service.

Middleware creation:

  1. Create a file with the directory to store your own middleware, this one is used as an interceptor (Node middle layer core);

6. Start writing this middleware:

interceptor.js

const log = require('.. /util/log'); // Reference the async library. const async = require('async'), NO_TOKEN = [// No token verification interface is required'/api/login'], // interface list URL = require('.. /config'); /* Const interceptor = (req, res,next) =>{res.result = {code: 200, data:""
  }
  console.log('Request interception');
  log.info("********* request intercept **********");
  //log.info("HOST:" + req.headers.host);
  log.info("Authorization:" + req.headers['authorization']); 
  // res.send('**********repoert******');

  try {
    console.log('Into');
    const origina_url = req.originalUrl;
    const method = req.method;
    log.info(origina_url);
    log.info(method);
    letCount = 0, // matchUrl = {}; // Save the matching routing rule //if(NO_TOKEN.indexOf(origina_url) < 0){
    //   if(req.headers){
    //     if(! req.headers['authorization'] || req.headers['authorization'] = =' '){
    //       log.warn('Request interface without Token');
    //       console.log('Request interface without Token');
    //       res.result['code'] = 403;
    //       // next();
    //       return; //} //} log.info(' carries token '); log.info(req.query); // Match: URL + request mode + parameterfor(let i = 0; i < URL.length; i++){
      
      let el = URL[i],
        url = el['url'].type = el['type'];
        log.info(url);
        log.info(method);
        log.info(type);
        log.info(url.test(origina_url));
        
        if(url.test(origina_url) && type.test(method)){
          log.info('Entered the match'// Verify the parameters of the POST requestif(method ! = ='GET') {let init_params = el['params'], init_params_length = init_params.length, request_params = Object.keys(req.body), request_params_length = request_params.length; // If the length of the request parameter is inconsistent with the length of the public parameter, the loop will be brokenif(request_params_length ! == init_params_length){ log.warn("Request parameter length inconsistent with public parameter length:" + request_params_length + "-" + init_params_length);
              console.log("Request parameter length inconsistent with public parameter length:" + request_params_length + "-" + init_params_length);
              continue; } // Compare request parameters with public parameters only when the public parameter length is not 0. // If the public parameter length is 0, the POST request does not require parameters and is treated as a GET requestif(init_params_length ! = = 0) {letparams_count = 0; // The argument matches the counterfor(let sub_i = 0; sub_i < request_params_length; sub_i++){
                letitem = request_params[sub_i]; // If the request parameter matches one of the public parameters, the counter ++;if(init_params.indexOf(item) ! = -1){ params_count++; }} // If the length of the parameter matching counter is inconsistent with that of the public parameter, the loop will be brokenif(params_count ! == init_params_length){ log.info('========== request parameters do not match public parameters ========== ');
                log.info('Request parameters:' + request_params);
                log.info('Public parameters:' + init_params);
                log.info('========== request parameters do not match public parameters ==========');
                continue;
              }
              
            }
            
          }
          count++;
          matchUrl = el;

          break;
        } else {
          console.log('Not matching');
          log.info('Not matching'); }} // If the match is greater than 0, the packet is forwardedif(count > 0){
      log.info('Matching items exist:'+ matchUrl.name); // Get the request parameterslet request_params = JSON.stringify(method == "GET"? req.query : req.body); // Request the background interface servicelet target = matchUrl['target'], target_length = target.length; //async library control flowif(target_length > 0){
        let async_func = [
          function (cb){
            let _params = JSON.parse(request_params);
            
            log.info('Pass argument:'+ request_params); // Check whether there is an incoming token. If so, set the token. req.headers['authorization']?function(){
              log.info('Token passed in:' + req.headers['authorization']);
              _params['authorization'] = req.headers['authorization']; } () :function(){
              log.info('No token passed in')
            }();
            
            cb(null, _params);
          }
        ].concat(target);
        
        log.info(target);
        async_func = async_func.concat([
          function(data,cb){
            log.info('Return front-end data:'+ JSON.stringify(data)); cb(null, data); }]); // Waterfall: Executes a set of functions sequentially. Each function produces a value that is passed to the next one. async.waterfall(async_func, (err, resultend)=>{if(err){
            res.result['code'] = err['httpStatus'];
            next();
          }
          res.result['code'] = 200;
          res.result['data'] = resultend;
          next();
        })
      }
    }
  }
  catch(err){
    log.error('======== NODE server abnormal =========');
    log.error(err);
    let errCode = err.statusCode;
    switch(errCode){
      case 400:
        res.result['code'] = 400;
      break;
      default:
        res.result['code'] = 500;
    }
    next();
  }
}
module.exports = interceptor;  

Copy the code

Interface list division:

  1. Partition interface list:

index.js;

const $http = require('.. /util/superagent');
const ENV = require('.. /config/url.config')
letlogin = []; Login = [{// Front-end interface description name:'login'// Front-end interface request address URL: /^ /list /login$/ I, // request modetype: /^post$/ I, // public params: ['memberCellphone'.'loginPwd'], // Call the list of back-end interfaces target:[function(initParam, cb){
        let headers = {
          "Content-Type":"application/json;",}$http('http://webapi.test.sxmaps.com/' + 'sapp/sapp-api/notfilter/member/login'.'post',initParam,{},function(err,res){
          if(err){
            cb(err,{});
            return false; } // Here we can arrange the data and splice it into data for the front endlet res_data = res;
          cb(null, JSON.parse(res_data.text));
        })
        
      }
    ]
  }
]
module.exports = login;
Copy the code

8.$HTTP file encapsulation. This article uses the Superagent library.

Superagent is a lightweight, flexible, easy-to-read client request proxy module with a low learning curve, used in NodeJS environments. superagent: visionmedia.github.io/superagent/


//
const superagent = require('superagent'); const NODE_ENV = process.env.NODE_ENV; // module.exports = superagent /** * Request forwarding public methods *$http(url, method, data, callback) * @param {String} URL request address * @param {String} method request method * @param {Obejct} data request parameters, } @param {Function} callback callback */ const$http = (url,method,data,headers,callback)=>{
  const URL =  url;
  if(! url || ! method || ! data || ! callback){ throw new Error('========== Abnormal configuration of configuration file request parameters ==========');
    return false;
  }
  let _http = superagent;
  log.info('Forwarding background address:' + url);
  log.info('Forwarding background parameters:' + JSON.stringify(data));
  switch (method) {
    case 'get':
      _http = _http.get(url).query(data);
      break;
    
    case 'put':
      _http = _http.put(url).send(data);
      break;

    case 'delete':
      _http = _http.del(url).send(data);
      break;
    
    default:
      _http = _http.post(url).send(data);
      break;
  }
  _http.end((err,res)=>{
    callback(null, res);
  })
}
module.exports = $http;
Copy the code

Middleware loading:

9. Update app.js to make app use interceptor, app.use(interceptor);

  1. Process the data returned by the interceptor –>>
    app.use(interceptor);
    app.use((req,res,next)=>{
    
    }
    Copy the code

Such as:

app.use(interceptor);
app.use((req,res,next)=>{
  let code = res.result['code']; /* Disable cache */ res.setheader ('Cache-Control'.'no-store');
  switch(code){
    case 403:
      res.send({
        code:403,
        msg:'Please carry token'}); default: res.send(res.result['data']);
    break;
  }
  let t = new Date() - req.time,
      conntectStr = req.method + ' ' + req.url + ' ' + t + ' ms';
  log4js.info(conntectStr);
  next();
});
Copy the code

Environment variable Settings:

11. Setting environment variables: Run commands on the package.json command line in the root directory to execute different scripts:

Create a file that reads the URL address;

Pm2 run environment variable, create a PM2 file, set read configuration.

Watch is the file that PM2 listens on, and log_file is the output to the log. Instances are the number of running threads

Project launch:

  1. If you don’t want the port to be nodeJS 3000, you can map the domain name in nginx proxy.

The parameter verification of middleware is still to be perfected and not very reasonable.