杂记总结

杂记总结

1. 项目框架 express 理解

1.1 express response 有哪些方法:

res.send();
res.render();
res.sendFile();
res.set();
res.get()
res.status();
res.type();

01. res.send([body])

Sends the HTTP response.

The body parameter can be a Buffer object, a String, an object, or an Array. For example:

res.send(new Buffer('whoop'));
res.send({ some: 'json' });
res.send('<p>some html</p>');
res.status(404).send('Sorry, we cannot find that!');
res.status(500).send({ error: 'something blew up' });

02. res.render(view [, locals] [, callback])

Renders a view and sends the rendered HTML string to the client. 就是导出你的模板引擎中的文件如:ejs、jade等

Optional parameters(可选参数): - locals: an object whose properties define local variables for the view. - callback, a callback function. If provided, the method returns both the possible error and rendered string, but does not perform an automated response. When an error occurs, the method invokes next(err) internally.

// send the rendered view to the client
res.render('index');

// if a callback is specified, the rendered HTML string has to be sent explicitly
res.render('index', function(err, html) {
  res.send(html);
});

// pass a local variable to the view
res.render('user', { name: 'Tobi' }, function(err, html) {
  // ...
});

03. res.sendFile(path [, options] [, fn])

Transfers the file at the given path. Sets the Content-Type response HTTP header field based on the filename’s extension. Unless the root option is set in the options object, path must be an absolute path of the file.

Here is an example of using res.sendFile with all its arguments.

app.get('/file/:name', function (req, res, next) {

  var options = {
    root: __dirname + '/public/',
    dotfiles: 'deny',
    headers: {
        'x-timestamp': Date.now(),
        'x-sent': true
    }
  };

  var fileName = req.params.name;
  res.sendFile(fileName, options, function (err) {
    if (err) {
      console.log(err);
      res.status(err.status).end();
    }
    else {
      console.log('Sent:', fileName);
    }
  });

})  

04. res.set(field [, value])

Sets the response’s HTTP header field to value. To set multiple fields at once, pass an object as the parameter.

res.set('Content-Type', 'text/plain');

res.set({
  'Content-Type': 'text/plain',
  'Content-Length': '123',
  'ETag': '12345'
})

Aliased as res.header(field [, value]).

05. res.get(field)

Returns the HTTP response header specified by field. The match is case-insensitive.

res.set('Content-Type', 'text/plain');
res.get('Content-Type'); // => "text/plain"

06. res.status(code)

Use this method to set the HTTP status for the response. It is a chainable alias of Node’s response.statusCode.

res.status(403).end();
res.status(400).send('Bad Request');
res.status(404).sendFile('/absolute/path/to/404.png');

07. res.type(type)

Sets the Content-Type HTTP header to the MIME type as determined by mime.lookup() for the specified type. If type contains the “/” character, then it sets the Content-Type to type.

res.type('.html');              // => 'text/html'
res.type('html');               // => 'text/html'
res.type('json');               // => 'application/json'
res.type('application/json');   // => 'application/json'
res.type('png');                // => image/png:

1.2. 什么是错误优先的回调函数?

错误优先的回调函数用于传递错误和数据。第一个参数始终应该是一个错误对象, 用于检查程序是否发生了错误。其余的参数用于传递数据。例如:

fs.readFile(filePath, function(err, data) {  
    if (err) {
        //handle the error
    }
    // use the data object
});

1.3. 如何用Node监听80端口

这题有陷阱!在类Unix系统中你不应该尝试去监听80端口,因为这需要超级用户权限。 因此不推荐让你的应用直接监听这个端口。

目前,如果你一定要让你的应用监听80端口的话,你可以有通过在Node应用的前方再增加一层反向代理 (例如nginx)来实现,如下图所示。否则,建议你直接监听大于1024的端口。 > 方向代理: 指的是以代理服务器来接收Internet上的连接请求,然后将请求转发给内部网络上的服务器, 并且将服务器返回的结果发送给客户端。

image


2. restful 接口理解

2.1 什么是 restful 接口

一句话:URL定位资源,用HTTP动词(GET,POST,DELETE,DETC)描述操作。

为什么要用 restful 结构呢?

近年来移动互联网的发展,各种类型的Client层出不穷,RESTful可以通过一套统一的接口为 Web,iOS和Android提供服务。另外对于广大平台来说,比如Facebook platform,微博开放平台,微信公共平台等,它们不需要有显式的前端,只需要一套提供服务的接口,于是RESTful更是它们最好的选择。在RESTful架构下:

image

达到一个目的或者起到的作用 就是:

  • 看Url就知道要什么
  • 看http method就知道干什么
  • 看http status code就知道结果如何

首先 REST 是所有Web应用都应该遵守的架构设计指导原则。

Representational State Transfer,翻译是”表现层状态转化”。

面向资源是REST最明显的特征,对于同一个资源的一组不同的操作。资源是服务器上一个可命名的抽象概念,资源是以名词为核心来组织的,首先关注的是名词。

REST要求,必须通过统一的接口来对资源执行各种操作。对于每个资源只能执行一组有限的操作。(7个HTTP方法:GET/POST/PUT/DELETE/PATCH/HEAD/OPTIONS) > GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源。

总之:符合REST设计标准的API,即RESTful API。REST架构设计,遵循的各项标准和准则,就是HTTP协议的表现,换句话说,HTTP协议就是属于REST架构的设计模式。

restful 标准接口:

一. URI规范:

  1. 不用大写;
  2. 用中杠 - 不用下杠 _ ;
  3. 参数列表要encode;
  4. URI中的名词表示资源集合,使用复数形式。
  5. 在RESTful架构中,每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词(特殊情况可以使用动词),而且所用的名词往往与数据库的表格名对应。

资源集合 vs单个资源

URI表示资源的两种方式:资源集合、单个资源。

资源集合:

/zoos //所有动物园

/zoos/1/animals //id为1的动物园中的所有动物

单个资源

/zoos/1//id为1的动物园

/zoos/1;2;3//id为1,2,3的动物园

避免层级过深的URI

在url中表达层级,用于 按实体关联关系进行对象导航 ,一般根据id导航。 过深的导航容易导致url膨胀,不易维护,

如 GET /zoos/1/areas/3/animals/4 ,尽量使用查询参数代替路径中的实体导航,如 GET/animals?zoo=1&area=3 ;

二. 版本

应该将API的版本号放入到URI中

       https://api.example.com/v1/zoos

3. MVC 框架实现的理解

3.1. 项目中的 mvc 分别对应文件目录结构的哪些目录?

node.js express中的MVC模式

  • app.js : 入口文件
  • package.json : 工程信息以及模块依赖 通过npm安装模块时输入命令 : npm instal xxx –save , 会自动把模块信息保存在package.jason中
  • node_modules : 存放模块
  • public : 存放image , css , js 等文件
  • routes : 存放路由文件
  • views : 存放视图文件
    • 通俗理解即前端
      • 如jade,ejs,html等(个人使用jade)
  • 存放可执行文件
1. Model
  • node提供的模块,中间件,在用express创建项目时,产生node_modules即表示M层,即Model
  • 模块如jade,mongoose,morgan,body-parser等等

    2. View
  • express生成项目时会产生views,即前端 ejs、jade等

    3. Controller
  • 即视图向控制器发出请求,由控制器选择相应的模型来处理

  • 模型返回的结果给控制器,由控制器来选择合适的视图,生成界面给用户

  • 如 通过res.render来渲染jade文件


4. 数据库理解

4.1. knex 中怎么处理 join 查询和子查询。

4.2 insert 和 update 操作返回值是什么,代表什么?


## 5. 怎么充分利用多核 CPU 方式提升性能

Node 虽然没有提供多线程用于计算支持,但是还是以下两个方式来充分利用CPU:

  • Node 可以通过编程 C/C++ 扩展的方式更高效地利用CPU,将一些 V8 不能做到性能极致的地方通过 C/C++ 来实现。

  • 可以通过创建 子线程 (child proccesses)的方式,将一部分 Node 进程当做常驻服务用于计算,然后利用进程间的消息来传递结果,将计算与I/O分离,这样就能充分利用多核CPU。

Node 提供了child_process 模块,并且也提供了 child_process.fork() 函数供我们实现进场的复制。

建立worker.js文件

const http = require('http');

http.createServer(function (req, res) {
    res.writeHead(200, {'Conent-Type': 'text/plain'});
    res.end('Hello world\n');
}).listen(Math.round((1 + Math.random()) * 1000), '127.0.0.1');

运行 node worker.js

master.js 文件

const fork = require('child_process').fork;
const cpus = require('os').cpus();

for (let i = 0; i < cpus.length; i++) {
    fork('./worker.js');
}

并运行 node master.js

这段代码会根据当前机器上的CPU数量复制出对应Node进程数。

可以通过 psaux | grep worker.js 查看到进程的数量。

这样的解决方案就是*nix系统上最经典的Master-Worker模式,又称为主从模式。

这种典型并行处理业务模式的分布式架构具备较好的可伸缩性(可伸缩性实际上是和并行算法以及并行计算机体系结构放在一起讨论的。某个算法在某个机器上的可扩放性反映该算法是否能有效利用不断增加的CPU。)和稳定性。主进程不负责具体的业务处理,而是负责调度和管理工作进程,工作进程负责具体的业务处理,所以,工作进程的稳定性是开发人员需要关注的。

image

通过fork()复制的进程都是一个独立的进程,这个进程中有着独立而全新的V8实例。虽然Node提供了fork()用来复制进程使每个CPU内核都使用上,但是依然要记住fork()进程代价是很大的。好在Node通过事件驱动在单个线程上可以处理大并发的请求。

  • 注意:这里启动多个进程只是为了充分将CPU资源利用起来,而不是为了解决并发问题。 关于本文具体内容可参见 朴灵 的 《深入浅出Node.js》P238.