前端的独立

博客分类: 原创

前端的独立

想要用node搭建服务器已经说了很久了。但是至今没有实现。一方面是对未知世界的恐惧,另一方面是时间不够,项目不允许。这次有这么一个机会自己就尝试搞一搞。搞了一天目前是前后端已经调通。由于没有安装数据库,所以还在等待。对今天的成果进行整理。

##建立项目

nodenpm就不过多赘述了。首先我们需要安装express,官方解释:基于Node.js平台的快速、灵活、简洁的web开发框架,官方网站。我用的是4.x

PS:后面的安装都是基于npm的,但由于npm很慢,所以就搞了个淘宝的镜像,安装请参照cnpm

安装express

cnpm install -g express-generator # 这个是全局安装

接下来就是使用express来初始化项目。

express -e nodejs-demo  # 创建项目 nodejs-demo 是项目名称

初始化完项目之后。仅仅是基础框架加载完了。但是依赖可能还没有加载完成。如果项目非常明确可以在项目里的package.json这个文件中写好自己对于文件的依赖,然后初始化依赖。

cd nodejs-demo && npm install

加载完成之后就可以启动项目了,启动方式有多种。最主要的就是要用node执行bin/www

npm start # 因为package.json中配置了start,所以这种启动方式是看怎么配置的
# 如果直接打开bin在www中启动也可以,但是由于express版本的不同可能会造成日志找不到路径的问题,所以建议采用下面两种配置
node ./bin/www # 用node来启动
DEBUG=nodejs-demo:* ./bin/www # 用debug方式启动
# 两种启动方式打出来的日志不同

最简单的应用已经启动了,这个时候访问localhost:3000就已经可以看到页面了。同时命令行中还可以看到相关于这个请求的日志。访问到的是routes/index.js这个文件。这个文件读取的又是view/index.xxx,由于模板不同,xxx也会不同。这个解析过程后面有分解。首先要了解页面的请求是怎么被拦截到本地的node服务上的。然后再看拦截到后又是怎么一步步到route再到view的。

chrome浏览中输入一个网址之后的简单经历

####DNS查询####
1、在浏览器中输入www.xxx.com域名,操作系统会先检查自己本地的hosts文件是否有这个网址映射关系,如果有,就先调用这个IP地址映射,完成域名解析。
2、如果hosts里没有这个域名的映射,则查找本地DNS解析器缓存,是否有这个网址映射关系,如果有,直接返回,完成域名解析。
3、如果hosts与本地DNS解析器缓存都没有相应的网址映射关系,首先会找TCP/ip参数中设置的首选DNS服务器,在此我们叫它本地DNS服务器,此服务器收到查询时,如果要查询的域名,包含在本地配置区域资源中,则返回解析结果给客户机,完成域名解析,此解析具有权威性。
4、如果要查询的域名,不由本地DNS服务器区域解析,但该服务器已缓存了此网址映射关系,则调用这个IP地址映射,完成域名解析,此解析不具有权威性。
5、如果本地DNS服务器本地区域文件与缓存解析都失效,则根据本地DNS服务器的设置(是否设置转发器)进行查询,如果未用转发模式,本地DNS就把请求发至13台根DNS,根DNS服务器收到请求后会判断这个域名(.com)是谁来授权管理,并会返回一个负责该顶级域名服务器的一个IP。本地DNS服务器收到IP信息后,将会联系负责.com域的这台服务器。这台负责.com域的服务器收到请求后,如果自己无法解析,它就会找一个管理.com域的下一级DNS服务器地址(xxx.com)给本地DNS服务器。当本地DNS服务器收到这个地址后,就会找xxx.com域服务器,重复上面的动作,进行查询,直至找到www.xxx.com主机。
6、如果用的是转发模式,此DNS服务器就会把请求转发至上一级DNS服务器,由上一级服务器进行解析,上一级服务器如果不能解析,或找根DNS或把转请求转至上上级,以此循环。不管是本地DNS服务器用是是转发,还是根提示,最后都是把结果返回给本地DNS服务器,由此DNS服务器再返回给客户机
####三次握手建立TCP连接####
####客户端发起http请求####
####本地node服务接收到请求####
####根据路由将相应的模板文件渲染好之后组成html片段返回####
####浏览器接受到html片段,进行翻译并开始请求其中的资源,如js、css####
####请求到资源开始渲染####

所以我们基本上可以知道,我们本地启动的服务是当我们读到host的时候取得了ip,并且得知了ip是本机的。然后本地的node服务发现相应的端口就是自己在监听的,然后就将服务转向本地。然后我们详细看一下。express重要的文件

package.json

基本的配置,更多的是项目相关的依赖

app.js

// 加载依赖库,原来这个类库都封装在connect中,现在需地注单独加载
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

// 加载路由控制
var routes = require('./routes/index');
var users = require('./routes/users');

// 创建项目实例
var app = express();

// 定义EJS模板引擎和模板文件位置,也可以使用jade或其他模型引擎
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

// 定义icon图标
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
// 定义日志和输出级别
app.use(logger('dev'));
// 定义数据解析器
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
    extended: false
}));
// 定义cookie解析器
app.use(cookieParser());
// 定义静态文件目录
app.use(express.static(path.join(__dirname, 'public')));

// 匹配路径和路由
app.use('/', routes);
app.use('/users', users);

// 404错误处理
app.use(function(req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});
// 错误的句柄
// 开发环境,500错误处理和错误堆栈跟踪
if (app.get('env') === 'development') {
    app.use(function(err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
    });
}
// 生产环境,500错误处理
app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});

bin/www

// 依赖加载
var app = require('../app');
var debug = require('debug')('nodejs-demo:server');
var http = require('http');
// 定义启动端口
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
// 创建HTTP服务器实例
var server = http.createServer(app);
// 启动网络服务监听端口
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
// 端口标准化函数
function normalizePort(val) {
    var port = parseInt(val, 10);
    if (isNaN(port)) {
        // named pipe
        return val;
    }
    if (port >= 0) {
        // port number
        return port;
    }
    return false;
}
// HTTP异常事件处理函数
function onError(error) {
    if (error.syscall !== 'listen') {
        throw error;
    }

    var bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port;

    // handle specific listen errors with friendly messages
    switch (error.code) {
        case 'EACCES':
            console.error(bind + ' requires elevated privileges');
            process.exit(1);
            break;
        case 'EADDRINUSE':
            console.error(bind + ' is already in use');
            process.exit(1);
            break;
        default:
            throw error;
    }
}
// 事件绑定函数
function onListening() {
    var addr = server.address();
    var bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port;
    debug('Listening on ' + bind);
}

github地址

目前已用express搭建了两个项目,已经沉浸在突然感觉手脚被释放的赶脚中。后面应该会对node在服务器上的部署总结一下。最后应该会学习node的底层,现在仅仅是停留在会用的阶段