Node.js 环境 v6.x+ WebStorm/Sublime/Atom/Vim

  1. Node.js 6.X对ES 6的规范的支持度99%
  2. Node.js es6特性
  3. 由于前端与后端的运行环境不同,使用Node.js后端编码方式在前端中不一定有效。因此,在浏览器环境中使用es6时,需要对Android/chrome/ios等支持度有个考量。

express文件目录规范

├── app.js # 应用的主入口
├── bin  # 启动脚本
├── node_modules # 依赖的模块
├── package.json # node模块的配置文件
├── public # 静态资源,如css、js等存放的目录
├── routes # 路由规则存放的目录
├── config.js or config/ 配置文件
├── controllers/ 业务逻辑相关
├── common业务公共资源 必须(MUST)
├── lib 公共资源
├── test/ 测试
├── models //数据库/应用模型文件
├── proxy // 数据代理目录
├── tools //工具文件目录
└── views # 模板文件存放的目录

App镜像

  • 将代码打包到容器中,开放端,并配置环境变量
  • 包含 Node js\ pm2 \ curl \ network-tools \ git
  • ENV env development 正式发布时 改为 ENV env product

REST-API 规范

1.路径(Endpoint)

路径又称”终点”(endpoint),表示API的具体网址。 在RESTful架构中,每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表格名对应。一般来说,数据库中的表都是同种记录的”集合”(collection),所以API中的名词也应该使用复数。 举例来说,有一个API提供动物园(zoo)的信息,还包括各种动物和雇员的信息,则它的路径应该设计成下面这样。 https://api.example.com/v1/zoos https://api.example.com/v1/animals https://api.example.com/v1/employees

2.HTTP动词

对于资源的具体操作类型,由HTTP动词表示。
常用的HTTP动词有下面五个(括号里是对应的SQL命令)。
GET(SELECT):从服务器取出资源(一项或多项)。
POST(CREATE):在服务器新建一个资源。
PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
DELETE(DELETE):从服务器删除资源。
还有两个不常用的HTTP动词。
HEAD:获取资源的元数据。
OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的。
下面是一些例子。
GET /zoos:列出所有动物园
POST /zoos:新建一个动物园
GET /zoos/ID:获取某个指定动物园的信息
PUT /zoos/ID:更新某个指定动物园的信息(提供该动物园的全部信息)
PATCH /zoos/ID:更新某个指定动物园的信息(提供该动物园的部分信息)
DELETE /zoos/ID:删除某个动物园
GET /zoos/ID/animals:列出某个指定动物园的所有动物
DELETE /zoos/ID/animals/ID:删除某个指定动物园的指定动物

3.过滤信息(Filtering)

如果记录数量很多,服务器不可能都将它们返回给用户。API应该提供参数,过滤返回结果。
下面是一些常见的参数。
?limit=10:指定返回记录的数量
?offset=10:指定返回记录的开始位置。
?page=2&per_page=100:指定第几页,以及每页的记录数。
?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。
?animal_type_id=1:指定筛选条件
参数的设计允许存在冗余,即允许API路径和URL参数偶尔有重复。比如,GET /zoo/ID/animals 与 GET /animals?zoo_id=ID 的含义是相同的。

4.状态码(Status Codes)

服务器向用户返回的状态码和提示信息,常见的有以下一些(方括号中是该状态码对应的HTTP动词)。
200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
204 NO CONTENT - [DELETE]:用户删除数据成功。
400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。
状态码的完全列表参见这里。

5.错误处理(Error handling)

如果状态码是4xx,就应该向用户返回出错信息。一般来说,返回的信息中将error作为键名,出错信息作为键值即可。
{
    error: "Invalid API key"
}

6.返回结果

针对不同操作,服务器向用户返回的结果应该符合以下规范。
GET /collection:返回资源对象的列表(数组)
GET /collection/resource:返回单个资源对象
POST /collection:返回新生成的资源对象
PUT /collection/resource:返回完整的资源对象
PATCH /collection规范 /resource:返回完整的资源对象
DELETE /collection/resource:返回一个空文档

7.Hypermedia API

RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。 比如,当用户向api.example.com的根目录发出请求,会得到这样一个文档。

{"link": {
  "rel":   "collection https://www.example.com/zoos",
  "href":  "https://api.example.com/zoos",
  "title": "List of zoos",
  "type":  "application/vnd.yourformat+json"
}}

上面代码表示,文档中有一个link属性,用户读取这个属性就知道下一步该调用什么API了。rel表示这个API与当前网址的关系(collection关系,并给出该collection的网址),href表示API的路径,title表示API的标题,type表示返回类型。 Hypermedia API的设计被称为HATEOAS。Github的API就是这种设计,访问api.github.com会得到一个所有可用API的网址列表。

{
  "current_user_url": "https://api.github.com/user",
  "authorizations_url": "https://api.github.com/authorizations",
  // ...
}

从上面可以看到,如果想获取当前用户的信息,应该去访问api.github.com/user,然后就得到了下面结果。

{
  "message": "Requires authentication",
  "documentation_url": "https://developer.github.com/v3"
}

8.其他

(1)API的身份认证应该使用OAuth 2.0框架。

9.Restful验证

(1) 对于Object对象的验证,主要在第一个模块前添加Put\Post\Path的参数检查和对象检测 示例,检查Monitor路由模块

```
        get  config/monitors
        put  config/monitors
        post config/monitors
        path config/monitors

        ...routes
``` ### 前端 规范  (1)由Angularjs/Vue 开发  (2)由WebPackage 打包压缩的文件,存放在原有需要打包文件的顶层目录 bin/目录下(不推荐改动目录结构) > 前端 -> 后端

模块间的引用-订阅设计或观察者模式

  1. 添加主机地址 Ip,host均为Unique,前端请求需要加超时设置
  2. 各模块之间的调用,通过该发布-订阅设计或观察者模式来解决耦合问题
    • 具体代码 参考《javascritp 设计模块与开发实践》 解决了  1.全局事件冲突 – 引入命名空间 2.离线转发
  3. 全局模块的引入,一般编写在执行文件(app.js)代码的第一行,避免各种执行顺序而产生的Bug

模块间的通用信息结构

  1. 在模块之,由于耦合的原理,或调用的原理,需要调用某个模块中的数据结构-常量很多,有时对应的数据结构需要统一。为些,在模块中暴露出一些信息结构是有必须要的。

Dockerfile编写规范(参考Dockerhub官方示例

  1. 通过apt-get 中source-list安装完成后,将该source.list文件删除,减少镜像大小为准
  2. 辅助工具下载软件,同样在安装完成后,删除该辅助软件
  3. 为容器中的Entrypoint定制用户,由定制的用户下来运行该软件。并使用GOSU来实现
  4. 为该运行的软件,编写环境变量,方便变更软件版本
  5. 编写docker-entrypoint.sh为指定的entrypoint命令的执行文件

数据库设计

  1. 删除操作,不使用物理删除,使用标记删除,如添加字段validate,defaultvalue:true
  2. 所有表一般自带三个字段created_at\updated_at以及uuid生成的id
  3. 联表查询(内联、外联、自联)分析
  4. 范式和反范式的对比 范式化模型 数据没有冗余,更新容易 当表的数量比较多,

    查询设计需要很多关联模型(join)时,会导致查询性能低下

    反范式化模型 数据冗余将带来很好的读取性能

    (因为不需要join很多表,而且通常反范式模型很少做更新操作)

    需要维护冗余数据,从目前NoS QL的发展可以看到,

    对磁盘空间的消耗是可以接受的

GIT规范

  1. 当没有直接PUSH权限时,通过fork来获取的代码,再clone.减少不必要的麻烦
  2. git .ignore注意添加node_module目录,减少不必要的上传文件,同时可以减少出错机会。
  3. 使用rebase而非merge来拉取上游修改,当切换分支时,工作区未完成某个模块时,可以使用git stash来暂存工作区内容,切换回来后,使用git stash pop来获取暂存的内容。
  4. 当有多个开发者使用不同的操作系统时,会有不同的LF/CRLF等问题,些时,需要添加 .gitattributes 文件
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto

# Explicitly declare text files you want to always be normalized and converted
# to native line endings on checkout.
*.html text eol=lf
*.js   text eol=lf
*.json text eol=lf
*.less text eol=lf
*.md   text eol=lf
*.svg  text eol=lf
*.xml  text eol=lf

# Declare files that will always have CRLF line endings on checkout.
*.sln text eol=crlf

# Denote all files that are truly binary and should not be modified.
*.png binary
*.jpg binary

# Refreshing a repository after changing line endings
# The best way to automatically configure your repository's line endings is to first backup your files with Git, delete every file in your repository (except the .git directory), and then restore the files all at once.

# Save your current files in Git, so that none of your work is lost.

# git add . -u
# git commit -m "Saving files before refreshing line endings"
# Remove every file from Git's index.

# git rm --cached -r .
# Rewrite the Git index to pick up all the new line endings.

# git reset --hard
# Add all your changed files back, and prepare them for a commit. This is your chance to inspect which files, if any, were unchanged.

# git add .
# It is perfectly safe to see a lot of messages here that read
# "warning: CRLF will be replaced by LF in file."
# Commit the changes to your repository.

# git commit -m "Normalize all the line endings"

数据校验

对于一个程序来说,适当的输入才有对应的输出。因此,输入的校验是非常常用的东西。在Nodejs下有几个比较有名的库validator\joi两个库,两者适用的场景不同。前者对应某个字段,后都对应一个obj。在express下有对就应的封装express-joi

NODE-JS应用开发中环境变量或配置文件的应用的应用

经典代码如下

  1. var port = process.env.PORT   “80”

模块API的调用设计

  1. 在调用者调用被调用者,一般使用callback,但是在2016年es6定制promise规范后,一般使用promise/bluebird来封装非阻塞接口。对于已经封装好的第三方库,使用callback的API封闭示例:
var redis = require("redis");
var Promise = require("bluebird");
Promise.promisifyAll(redis.RedisClient.prototype);
Promise.promisifyAll(redis.Multi.prototype);
  1. 在Node.js后端中,真正解决回调用问题的是Generator.

后端压力测试

在后端rest-ful api 完成后,进行压测是有必要的,可以清淅的了解该后端的阀值,可以方便的进行预处理与发送警报。 推荐的web压力测试工具集有:

  1. Grinder – Grinder是一个开源的JVM负载测试框架,它通过很多负载注射器来为分布式测试提供了便利。 支持用于执行测试脚本的Jython脚本引擎HTTP测试可通过HTTP代理进行管理。根据项目网站的说法,Grinder的 主要目标用户是“理解他们所测代码的人——Grinder不仅仅是带有一组相关响应时间的‘黑盒’测试。由于测试过程可以进行编码——而不是简单地脚本 化,所以程序员能测试应用中内部的各个层次,而不仅仅是通过用户界面测试响应时间。
  2. Pylot -Pylot是一款开源的测试web service性能和扩展性的工具,它运行HTTP 负载测试,这对容量计划,确定基准点,分析以及系统调优都很有用处。Pylot产生并发负载(HTTP Requests),检验服务器响应,以及产生带有metrics的报表。通过GUI或者shell/console来执行和监视test suites。
  3. Web Capacity Analysis Tool (WCAT) – 这是一种轻量级负载生成实用工具,不仅能够重现对 Web 服务器(或负载平衡服务器场)的脚本 HTTP 请求,同时还可以收集性能统计数据供日后分析之用。WCAT 是多线程应用程序,并且支持从单个源控制多个负载测试客户端,因此您可以模拟数千个并发用户。该实用工具利用您的旧机器作为测试客户端,其中每个测试客户端又可以产生多个虚拟客户端(最大数量取决于客户端机器的网络适配器和其他硬件)。您可以选择使用 HTTP 1.0 还是 HTTP 1.1 请求,以及是否使用 SSL。并且,如果测试方案需要,您还可以使用脚本执行的基本或 NTLM 身份验证来访问站点的受限部分。(如果您的站点使用 cookie、表单或基于会话的身份验证,那您可以创建正确的 GET 或 POST 请求来对测试用户进行身份验证。)WCAT 还可管理您站点可能设置的任何 cookie,所以配置文件和会话信息将永久保存。
  4. fwptt – fwptt 也是一个用来进行WEB应用负载测试的工具。它可以记录一般的请求,也可以记录Ajax请求。它可以用来测试 asp.net, jsp, php 或是其它的Web应用。
  5. JCrawler – JCrawler是一个开源( CPL) 的WEB应用压力测试工具。通过其名字,你就可以知道这是一个用Java写的像网页爬虫一样的工具。只要你给其几个URL,它就可以开始爬过去了,它用一种特殊的方式来产生你WEB应用的负载。这个工具可以用来测试搜索引擎对你站点产生的负载。当然,其还有另一功能,你可以建立你的网站地图和再点击一下,将自动提交Sitemap给前5名的搜索引擎!
  6. Apache JMeter – Apache JMeter是一个专门为运行和服务器装载测试而设计的、100%的纯Java桌面运行程序。原先它是为Web/HTTP测试而设计的,但是它已经扩展以支持各种各样的测试模块。它和用于HTTP和SQL数据库(使用JDBC)的模块一起运送。它可以用来测试静止资料库或者活动资料库中的服务器的运行情况,可以用来模拟对服务器或者网络系统加以重负荷以测试它的抵抗力,或者用来分析不同负荷类型下的所有运行情况。它也提供了一个可替换的界面用来定制数据显示,测试同步及测试的创建和执行。
  7. Siege -Siege(英文意思是围攻)是一个压力测试和评测工具,设计用于WEB开发这评估应用在压力下的承受能力:可以根据配置对一个WEB站点进行多用户的并发访问,记录每个用户所有请求过程的相应时间,并在一定数量的并发访问下重复进行。 Siege 支持基本的认证,cookies, HTTP 和 HTTPS 协议。
  8. http_load – http_load 以并行复用的方式运行,用以测试web服务器的吞吐量与负载。但是它不同于大多数压力测试工具,它可以以一个单一的进程运行,一般不会把客户机搞死。可以可以测试HTTPS类的网站请求。
  9. Web Polygraph – Web Polygraph这个软件也是一个用于测试WEB性能的工具,这个工具是很多公司的标准测试工具,包括微软在分析其软件性能的时候,也是使用这个工具做为基准工具的。很多招聘测试员的广告中都注明需要熟练掌握这个测试工具。
  10. OpenSTA – OpenSTA是一个免费的、开放源代码的web性能测试工具,能录制功能非常强大的脚本过程,执行性能测试。例如虚拟多个不同的用户同时登陆被测试网站。其还能对录制的测试脚本进行,按指定的语法进行编辑。在录制完测试脚本后,可以对测试脚本进行编辑,以便进行特定的性能指标分析。其较为丰富的图形化测试结果大大提高了测试报告的可阅读性。OpenSTA 基于CORBA 的结构体系,它通过虚拟一个proxy,使用其专用的脚本控制语言,记录通过proxy 的一切HTTP/S traffic。通过分析OpenSTA的性能指标收集器收集的各项性能指标,以及HTTP 数据,对系统的性能进行分析。

API-Doc/Doc

在整合项目基本完成后,需要生成一些项目文档以及Rest-Api接口文档。而文档一般由代码中的方法/模块/语句等注释语句完成,而不需要手写一个doc文档。 推荐工具:

  1. ApiDoc-Github
  2. [YUIDoc]/[JSDuck]/jsdoc-Github

404标准页

腾讯的404页面,并没有官方声明的那样,可以定制化。因此,对于部分的js代码,需要由开发者来修改完成定制化需求。参考http://blog.songjz.cn/teng-xun-404/ 添加如下代码

<script type="text/javascript" src="http://www.qq.com/404/search_children.js" charset="utf-8"></script>

开发流程

  1. 横向:需求分析 -> 项目特点(计算密集、IO密集、大数据应用)-> 调研框架、工具链接、技术难点、某技术最佳实践 => Demo测试 => 项目结构组织
  2. 纵向:最小原型(核心功能)-注意代码可扩展性 -> 原型