• express+gulp构建项目(二)启动项目和主文件


    这一次整理的内容是项目主文件和如何启动项目。

    启动项目

    通过nodejs官网的例子https://nodejs.org/docs/latest-v4.x/doc/api/synopsis.html我们可以知道,在项目目录下打开终端命令行,并且输入如下命令即可启动服务:

    node app.js

    其中app.js是项目的主文件。

    那是因为这个主文件里面有创建服务和监听端口的语句:

    const http = require('http');
    
    const hostname = '127.0.0.1';
    const port = 3000;
    
    const server = http.createServer((req, res) => {
      res.statusCode = 200;
      res.setHeader('Content-Type', 'text/plain');
      res.end('Hello World
    ');
    });
    
    server.listen(port, hostname, () => {
      console.log(`Server running at http://${hostname}:${port}/`);
    });

    而我们现在使用的是express框架,它的写法有些不一样。express4.0之后的版本,项目目录下会有bin/这个目录,这个目录专门用于自定义启动脚本,这样就把与启动服务的代码和主文件分离了,而且你可以定义多个启动脚本,而不用去修改app.js这个主文件。

    我们来看看bin/www这个文件是什么内容:

    #!/usr/bin/env node

    var app = require('../app'); app.set('port', PORT || 3000); var server = app.listen(app.get('port'), function() { console.log('Express server listening on port ', app.get('port'), " with pid ", process.pid); });

    然后我们逐行解释一下:

    #!/usr/bin/env node
    /*这一句是写给类unix系统看的
    *如果用户没有将nodejs装在默认的/usr/bin路径里
    *当系统看到这一行的时候,首先会到env设置里查找nodejs的安装路径
    *再调用对应路径下的解释器程序完成操作
    */
    var app = require('../app');
    //引入app主应用
    app.set(
    'port', PORT || 3000); //设置端口为环境变量.env文件里的PORT,如果.env里没有,就默认3000
    var server = app.listen(app.get('port'), function() { console.log('Express server listening on port ', app.get('port'), " with pid ", process.pid); });
    /*app.listen(path,[callback])的写法是启动一个socket连接,然后在给定的端口上监听连接
    *app.get(name)的写法是获取app设置,设置的时候通过app.set('port', 'my port');来设置。
    */

    package.json

    package.json文件描述了一个NPM包的所有相关信息,包括作者、简介、包依赖、构建等信息。格式必须是严格的json格式。

    {
      "name": "xia",
      "version": "0.0.1",
      "private": true,
      "scripts": {
        "start": "node ./bin/www",
        "dev": "./node_modules/.bin/gulp develop --gulpfile gulp_dev.js",
        "ci": "./node_modules/.bin/gulp test --gulpfile gulp_test.js",
        "assets": "./node_modules/.bin/gulp build --gulpfile gulp_build.js",
        "assets_dev": "./node_modules/.bin/gulp build --dev --gulpfile gulp_build.js",
        "watch": "./node_modules/.bin/gulp watch --gulpfile gulp_build.js"
      },
      "dependencies": {
        "async": "2.0.1",
        "body-parser": "1.13.3",
        "connect-multiparty": "2.0.0",
        "connect-redis": "3.0.2",
        "cookie": "0.2.3",
        "cookie-parser": "1.3.3",
        "crypto": "0.0.3",
        "dotenv": "1.2.0",
        "excel-export": "0.5.1",
        "express": "4.13.3",
        "express-session": "1.13.0",
        "formidable": "1.0.16",
        "glob": "5.0.15",
        "jsonfile": "2.2.2",
        "log4js": "0.6.35",
        "morgan": "1.6.1",
        "raven": "0.8.1",
        "request-promise": "1.0.2",
        "run-sequence": "1.1.3",
        "serve-favicon": "2.3.0",
        "sha1": "1.1.1",
        "swig": "1.4.2",
        "write-file-stdout": "0.0.2"
      },
      "devDependencies": {
        "gulp-nodemon": "2.0.2",
        "gulp": "3.9.0",
        "gulp-bower": "0.0.10",
        "gulp-clean": "0.3.1",
        "gulp-cssmin": "0.1.7",
        "gulp-eslint": "1.0.0",
        "gulp-if": "1.2.5",
        "gulp-uglify": "1.5.3",
        "gulp-rev-all-fixed": "0.8.24",
        "gulp-livereload": "3.8.0",
        "gulp-plumber": "1.0.0",
        "gulp-replace": "0.5.4",
        "gulp-rev-all": "0.8.21",
        "gulp-sass": "2.0.4",
        "compass-mixins": "0.12.7",
        "node-sass": "3.4.2",
        "yargs": "3.25.0"
      }
    }

    其中name和version是最重要的两个字段,也是发布到npm平台标示,必须有。

    其中private设置为true,这个包将不会发布到npm。

    scripts可以设置一些自定义的脚本,我们项目的启动服务,处理静态文件的命令就定义在这里。

    dependencies指定依赖的包,如果是开发中需要的包,可以指定在devDependencies,建议严格匹配包的版本。

    scripts中的脚本的写法前面都加上了./node_modules/.bin/是因为这里后面命令都是gulp构建工具的命令,而gulp包在devDependencies里,所以加上这个前缀。

    而后面的gulp build --gulpfile gulp_build.js这样的写法是gulp构建工具执行任务时的命令。

    app.js

    app.js就是node项目主文件。

    var express = require('express');
    var session = require('express-session');
    var redisStore = require('connect-redis')(session);
    var glob = require('glob');
    var path = require('path');
    var bodyParser = require('body-parser');

    var swig = require('swig'); var staticTag = require('./swig/static'); var morgan = require("morgan"); var app = express(); var client; app.locals.ENV = NODE_ENV; app.locals.ENV_DEV = (NODE_ENV === 'dev'); // view engine setup app.engine('html', swig.renderFile); app.set('view engine', 'html'); app.set('view cache', false); app.set('views', path.join(__dirname, 'views')); swig.setDefaults({cache: false}); swig.setDefaults({loader: swig.loaders.fs(__dirname + '/views')}); staticTag.init(swig); app.use(session({ cookie: { maxAge: 2502000 * 1000 }, name: 'lbn_sid', secret: 'what are you thinking?', store: new redisStore({ ttl: 2502000, url: REDIS_URL }), saveUninitialized: false, resave: false })); // app.use(morgan('combined')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true, limit: '10mb' })); app.use('/' + global.STATIC_URL, express.static(path.join(__dirname, STATIC_DIR))); var controllers = glob.sync('./controllers/*.js'); controllers.forEach(function (controller) { require(controller)(app); }); app.use(function (err, req, res, next) { res.locals = {env: NODE_ENV}; // treat as 404 if (err.message && (~err.message.indexOf('not found') || (~err.message.indexOf('Cast to ObjectId failed')))) { return next(); } res.status(500).render('500', { error: err.stack }); }); app.use(function (req, res, next) { res.status(404).render('404', { url: req.originalUrl, error: 'Not found' }); }); module.exports = app;

    我们来看看里面都是什么东西:

    var express = require('express'); //引入express框架
    var session = require('express-session'); //设置session的中间件
    var redisStore = require('connect-redis')(session); //实现redis存储session
    var glob = require('glob'); //使用类似shell的模式语法匹配文件路径
    var path = require('path'); //path模块用于处理和转换文件路径
    var bodyParser = require('body-parser'); //解析请求的body的中间件

    var swig = require('swig'); //swig模板引擎 var staticTag = require('./swig/static'); //swig模板相关设置 var morgan = require("morgan"); //控制台日志 var app = express(); //创建一个express应用 app.locals.ENV = NODE_ENV; //将环境变量NODE_ENV存在app.locals里 app.locals.ENV_DEV = (NODE_ENV === 'dev'); //是否是dev环境 // view engine setup app.engine('html', swig.renderFile); //使用swig渲染html文件 app.set('view engine', 'html'); //设置默认页面扩展名 app.set('view cache', false); //设置模板编译无缓存 app.set('views', path.join(__dirname, 'views')); //设置项目的页面文件,也就是html文件的位置 swig.setDefaults({cache: false}); //关闭swig模板缓存 swig.setDefaults({loader: swig.loaders.fs(__dirname + '/views')}); //从文件载入模板,请写绝对路径,不要使用相对路径 staticTag.init(swig); //这个init函数是自定义的,对swig模板做了一些自定义设置 app.use(session({ //设置session中间件的写法,session会存在服务端 cookie: { maxAge: 2502000 * 1000 //设置最大生命周期,过了这个时间后cookie会失效,单位毫秒 }, name: 'lbn_sid', //用来保存session的cookie名称 secret: 'what are you thinking?', //用来对session数据进行加密的字符串.这个属性值为必须指定的属性 store: new redisStore({ //设置session的存储仓库为redis数据库 ttl: 2502000, //redis session生命周期,单位秒 url: REDIS_URL //redis缓存服务地址 }), saveUninitialized: false, //false选项不会强制存储未初始化的session到redis里,未初始化意味着新的还没有修改的 resave: false //如果是true选项,强制重新存储session到redis里,即使session没有被修改,false意味着如果没有变化就不用重新存 })); // app.use(morgan('combined')); //morgan控制台日志,会在控制台输出所有http请求日志,combined是标准Apache日志格式
    app.use(bodyParser.json()); //bodyParser.json是用来解析请求体的json数据格式 app.use(bodyParser.urlencoded({ extended: true, limit: '10mb' })); /*bodyParser.urlencoded则是用来解析我们通常的form表单提交的数据,
    *也就是请求头中包含这样的信息: Content-Type: application/x-www-form-urlencoded
    *extended选项为true会使用qs library来解析数据,false会使用querystring来解析
    *limit选项限制请求体的大小

    */
    app.use(
    '/' + global.STATIC_URL, express.static(path.join(__dirname, STATIC_DIR))); //为静态资源的请求添加虚拟路径,只有请求静态资源的路径前加了global.STATIC_URL前缀后,才可请求成功
    var controllers = glob.sync('./controllers/*.js'); //获取到controllers文件夹下的所有js文件,这些文件里都是路由 controllers.forEach(function (controller) { require(controller)(app); }); //将所有路由循环到主文件中使其生效
    app.use(
    function (err, req, res, next) { //当请求出现500错误,渲染500错误页面 res.locals = {env: NODE_ENV}; // treat as 404 if (err.message && (~err.message.indexOf('not found') || (~err.message.indexOf('Cast to ObjectId failed')))) { return next(); } res.status(500).render('500', { error: err.stack }); }); app.use(function (req, res, next) { //当请求出现404错误,渲染404错误页面 res.status(404).render('404', { url: req.originalUrl, error: 'Not found' }); }); module.exports = app; //将app应用导出成模块

     这其中session的设置值得注意,session的设置写在了app.use()中,也就是中间件中,中间件也是路由,只是所有的请求都会经过它的处理。这里设置session时有一个cookie的设置,这个cookie就是session的唯一标示,是sessionId,也就是说,第一次访问网站的时候,在请求通过session设置的中间件时,响应头里会设置一个set-cookie来强制浏览器存储一个cookie,也就是在浏览器存下sessionId,然后会在node端新建一个session,这里浏览器存的sessionId和node端的session是对应关系,之后的请求也会经过session设置的中间件,此时的请求头里会自动带上浏览器的所有cookie,当中间件发现已经有sessionId的时候,就不会新建了,只用更新对应的session就可以了。

  • 相关阅读:
    #小练习 动态生成密码 分类: python 小练习 2013-08-15 16:25 314人阅读 评论(0) 收藏
    mysql中文乱码问题 分类: database 2013-08-15 14:03 330人阅读 评论(0) 收藏
    使用os.walk()方法 分类: python 小练习 2013-08-14 10:52 1465人阅读 评论(0) 收藏
    oracle 数据库转换成mysql工具:ora2mysqcn 分类: database 2013-08-14 10:21 541人阅读 评论(0) 收藏
    使用fileinput模块进行原地修改文件 分类: python 小练习 2013-08-13 16:47 618人阅读 评论(0) 收藏
    docker知识整理(备份)
    [DP] [模板] 01背包
    [模板][线段树]
    [Tree] [洛谷] P1030 求先序排列
    [Tree] [洛谷] P1087 FBI树
  • 原文地址:https://www.cnblogs.com/hahazexia/p/6027787.html
Copyright © 2020-2023  润新知