commit 878d9b63f64c96b445805c9774fd4f8df461dea7
Author: 轶哥
Date: Mon Jan 23 01:12:24 2017 +0800
v0.0.1
diff --git a/.babelrc b/.babelrc
new file mode 100644
index 0000000..51a8ae4
--- /dev/null
+++ b/.babelrc
@@ -0,0 +1,4 @@
+{
+ "presets": ["es2015", "stage-2"],
+ "plugins": ["transform-runtime"]
+}
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..9d08a1a
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,9 @@
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 0000000..34af377
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,2 @@
+build/*.js
+config/*.js
diff --git a/.eslintrc.js b/.eslintrc.js
new file mode 100644
index 0000000..934f7f2
--- /dev/null
+++ b/.eslintrc.js
@@ -0,0 +1,25 @@
+module.exports = {
+ root: true,
+ parserOptions: {
+ ecmaVersion: 6, //指定ECMAScript支持的版本,6为ES6
+ sourceType: 'module'
+ },
+ extends: 'standard',
+ plugins: [
+ 'html',
+ "promise"
+ ],
+ env: {
+ "node": true
+ },
+ rules: { // add your custom rules here
+ // allow console
+ "no-console": 0,
+ // allow paren-less arrow functions
+ 'arrow-parens': 0,
+ // allow async-await
+ 'generator-star-spacing': 0,
+ // allow debugger during development
+ 'no-debugger': 0
+ }
+}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..faf3925
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+.DS_Store
+node_modules/
+dist/
+npm-debug.log
+test/unit/coverage
+test/e2e/reports
+selenium-debug.log
+.idea/
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..930fc78
--- /dev/null
+++ b/README.md
@@ -0,0 +1,396 @@
+# Koa2 RESTful API 服务器脚手架
+
+这是一个基于Koa2的轻量级Resultful API Server脚手架,支持ES6。
+
+约定使用JSON格式传输数据,POST、PUT、DELET方法支持的Content-Type为application/x-www-form-urlencoded和multipart/form-data、application/json,可配置支持跨域。非上传文件推荐application/x-www-form-urlencoded。通常情况下返回application/json格式的JSON数据。
+
+可选用mongodb、redis非关系型数据库和PostgreSQL, MySQL, MariaDB, SQLite, MSSQL关系型数据库,考虑RESTful API Server的实际开发需要,这里通过sequelize.js作为ORM,同时提通过Promise执行SQL直接操作Mysql数据库的方法(不管什么方法,注意安全哦)。
+
+此脚手架只安装了一些和Koa2不冲突的搭建RESTful API Server的必要插件,附带每一个插件的说明。采用ESlint进行语法检查。
+
+因此脚手架主要提供RESTful API,故暂时不考虑前端静态资源处理。基本目录结构与vue-cli保持一致,可配合React、AngularJS、Vue.js等前端框架使用。在Cordova/PhoneGap中使用时需要开启跨域功能。
+
+**免责声明:** 此脚手架仅为方便开发提供基础环境,任何人或组织均可随意克隆使用,使用引入的框架需遵循原作者规定的相关协议(框架列表及来源地址在下方)。采用此脚手架产生的任何后果请自行承担,本人不对此脚手架负任何法律责任,使用即代表同意此条。
+
+目前暂未加入软件测试模块,下一个版本会加入该功能并提供集成方案。
+
+China大陆用户请自行优化网络。
+
+## 开发使用说明
+```
+$ git clone https://github.com/yi-ge/koa2-API-scaffold.git
+
+$ cd mv koa2-API-scaffold
+$ npm install
+$ npm run dev #可执行npm start跳过ESlint检查。
+```
+访问: http://127.0.0.1:3000/
+
+另外一种方式,如果你使用git仓库管理你的代码:
+
+```
+$ git clone https://github.com/yi-ge/koa2-API-scaffold.git
+
+$ mv koa2-API-scaffold `您的项目名称`
+$ cd `您的项目名称`
+$ rm -rf .git
+$ git init
+$ git remote add origin `您的git仓库地址`
+$ npm install
+$ npm run dev #可执行npm start跳过ESlint检查。
+```
+
+## 调试说明
+
+```
+$ npm start --debug
+
+Or
+
+$ npm start --debug
+```
+
+支持Node.js原生调试功能:https://nodejs.org/api/debugger.html
+
+## 开发环境部署
+
+生成node直接可以执行的代码到dist目录:
+```
+$ npm run build
+```
+
+```
+$ npm run production # 生产模式运行
+
+Or
+
+$ node dist/app.js
+```
+
+### PM2部署说明
+提供了PM2部署RESTful API Server的示例配置,位于“pm2.js”文件中。
+```
+$ pm2 start pm2.js
+```
+
+PM2配合Docker部署说明:
+http://pm2.keymetrics.io/docs/usage/docker-pm2-nodejs/
+
+### Docker部署说明
+```
+$ docker pull node
+$ docker run -itd --name RESTfulAPI -v "$PWD":/usr/src/app -w /usr/src/app node node ./dist/app.js
+```
+
+通过
+```
+$ docker ps
+```
+查看是否运行成功及运行状态
+
+### Linux/Mac 直接后台运行生产环境代码
+有时候为了简单,我们也这样做:
+```
+$ nohup node ./dist/app.js > logs/out.log &
+```
+
+查看运行状态(如果有"node app.js"出现则说明正在后台运行):
+```
+$ ps aux|grep app.js
+```
+
+查看运行日志
+```
+$ cat logs/out.log
+```
+
+监控运行状态
+```
+$ tail -f logs/out.log
+```
+
+### 配合Vue-cli部署说明
+Vue-cli(Vue2)运行"npm run build"后会在"dist"目录中生成所有静态资源文件。推荐使用Nginx处理静态资源以达最佳利用效果,然后通过上述任意一种方法部署RESTful API服务器。前后端是完全分离的,请注意Koa2 RESTful API Server项目中config/main.json里面的跨域配置。
+
+推荐的Nginx配置文件:
+```
+server
+ {
+ listen 80;
+ listen [::]:80;
+ server_name abc.com www.abc.com; #绑定域名
+ index index.html index.htm;
+ root /www/app/dist; #Vue-cli编译后的dist目录
+
+ location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
+ {
+ expires 30d;
+ }
+
+ location ~ .*\.(js|css)?$
+ {
+ expires 12h;
+ }
+
+ location ~ /\.
+ {
+ deny all;
+ }
+
+ access_log off; #访问日志路径
+ }
+```
+Docker中Nginx运行命令(将上述配置文件任意命名放置于nginx_config目录中即可):
+```
+$ docker run -itd -p 80:80 -p 443:443 -v `pwd`/nginx_config:/etc/nginx/conf.d nginx
+```
+
+## 引入插件介绍
+
+> 引入插件的版本将会持续更新
+
+引入的插件:
+`` koa nodemon babel-cli babel-register babel-plugin-transform-runtime babel-preset-es2015 babel-preset-stage-2 gulp gulp-eslint eslint eslint-config-standard eslint-friendly-formatter eslint-plugin-html eslint-plugin-promise ``
+
+"koa-bodyparser": "^3.2.0",
+"koa-compose": "^3.1.0",
+"koa-convert": "^1.2.0",
+"koa-favicon": "^2.0.0",
+"koa-json": "^1.1.3",
+"koa-logger": "^1.3.0",
+"koa-multer": "^1.0.0",
+"koa-router": "^7.0.1",
+"koa-session": "^3.3.1",
+"koa-static2": "^0.1.8",
+"koa-onerror": "^3.0.1",
+
+**koa**: HTTP框架
+ Synopsis: HTTP framework.
+ From: https://github.com/koajs/koa
+
+**babel-cli**: Babel编译ES6代码为ES5代码
+ Synopsis: Babel is a JavaScript compiler, ES6 to ES5.
+ From: https://github.com/babel/babel/tree/master/packages/babel-cli
+
+**babel-register**: Babel开发环境实时编译ES6代码
+ Synopsis: Babel hook.
+ From: https://github.com/babel/babel/tree/master/packages/babel-cli
+
+**babel-plugin-transform-runtime**: Babel配置ES6的依赖项
+**babel-preset-es2015**: 同上
+**babel-preset-stage-2**: 同上
+
+**gulp**: 基于流的自动化构建工具
+ Synopsis: Gulp is a toolkit for automating painful or time-consuming tasks.
+ From: https://github.com/gulpjs/gulp
+
+**gulp-eslint**: gulp的ESLint检查插件
+ Synopsis: A gulp plugin for ESLint.
+ From: https://github.com/adametry/gulp-eslint
+
+**gulp-nodemon**: 修改JS代码后自动重启
+ Synopsis: nodemon will watch the files in the directory in which nodemon was started, and if any files change, nodemon will automatically restart your node application.
+ From: https://github.com/remy/nodemon
+
+**eslint**: JavaScript语法检查工具
+ Synopsis: A fully pluggable tool for identifying and reporting on patterns in JavaScript.
+ From:
+
+**eslint-config-standard**: 一个ESlint配置
+ Synopsis: ESLint Shareable Config for JavaScript Standard Style.
+ From: https://github.com/feross/eslint-config-standard
+
+**eslint-friendly-formatter**: 使得ESlint提示在Sublime Text或iterm2中更友好,Atom也有对应的ESlint插件。
+ Synopsis: A simple formatter/reporter for ESLint that's friendly with Sublime Text and iterm2 "click to open file" functionality
+ From: https://github.com/royriojas/eslint-friendly-formatter
+
+**eslint-plugin-html**: 检查HTML文件中的JS代码规范
+ Synopsis: An ESLint plugin to extract and lint scripts from HTML files.
+ From: https://github.com/BenoitZugmeyer/eslint-plugin-html
+
+**eslint-plugin-promise**: 检查JavaScript promises
+ Synopsis: Enforce best practices for JavaScript promises.
+ From: https://github.com/xjamundx/eslint-plugin-promise
+
+**eslint-plugin-promise**: ESlint依赖项
+ Synopsis: ESlint Rules for the Standard Linter.
+ From: https://github.com/xjamundx/eslint-plugin-standard
+
+支持Koa2的中间件列表:https://github.com/koajs/koa/wiki
+
+其它经常配合Koa2的插件:
+**koa-nunjucks-2**:
+一个好用的模版引擎,可用于前后端,nunjucks。https://github.com/mozilla/nunjucks
+
+## 目录结构说明
+
+```bash
+.
+├── README.md
+├── .babelrc # Babel 配置文件
+├── .editorconfig # 编辑器风格定义文件
+├── .eslintignore # ESlint 忽略文件列表
+├── .eslintrc.js # ESlint 配置文件
+├── .gitignore # Git 忽略文件列表
+├── gulpfile.js # Gulp配置文件
+├── package.json # 描述文件
+├── pm2.js # pm2 部署示例文件
+├── build # build 入口目录
+│ └── dev-server.js # 开发环境 Babel 实时编译入口
+├── config
+│ └── main.js # 主配置文件(*谨防泄密!)
+├── src # 源代码目录,编译后目标源代码位于 dist 目录
+│ ├── app.js # koa 配置
+│ ├── config # 配置目录
+│ ├── controllers # 控制器
+│ ├── index.js # 入口文件
+│ ├── models # 模型
+│ ├── routes # 路由
+│ └── services # service
+└── logs # 日志目录
+```
+
+## 各类主流框架调用RESTful API的示例代码(仅供参考)
+
+### AngularJS (Ionic同)
+```
+$http({
+ method: "post",
+ url: "http://localhost:3000/xxx",
+ data: {para1:"para1",para2:"para2"},
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded'
+ }
+ }).success(function (data) {
+ }).error(function (data) {
+ });
+ ```
+
+### jQuery
+```
+$.ajax({
+ cache: false,
+ type: 'POST',
+ url: "http://localhost:3000/xxx",
+ data: {
+ para1: para1
+ },
+ async: false,
+ dataType: "json",
+ success: function (result) {
+ },
+ error: function (err) {
+ console.log(err);
+ }
+});
+
+// 上传文件
+//创建FormData对象
+var data = new FormData();
+//为FormData对象添加数据
+//
+$.each($('#inputfile')[0].files, function (i, file) {
+ data.append('upload_file', file);
+});
+$.ajax({
+ url: 'http://127.0.0.1:3000/api/upload_oss_img_demo',
+ type: 'POST',
+ data: data,
+ cache: false,
+ contentType: false, //不可缺
+ processData: false, //不可缺
+ success: function (data) {
+ console.log(data);
+ if (data.result == "ok") {
+ $("#zzzz").attr("src", data.img_url);
+ }
+
+ }
+});
+```
+
+### MUI
+```
+mui.ajax({ url: "http://localhost:3000/xxx", dataType: "json",
+ success: function(data){
+
+ },
+ error: function(data){
+ console.log("error!");
+ }
+});
+```
+
+### JavaScript
+```
+ var xhr = new XMLHttpRequest()
+ xhr.open("POST", "http://localhost:3000/xxx", true) //POST或GET,true(异步)或 false(同步)
+ xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
+ xhr.withCredentials = true
+ xhr.onreadystatechange = function () {
+ if (obj.readyState == 4 && obj.status == 200 || obj.status == 304) {
+ var gotServices = JSON.parse(xhr.responseText)
+ }else{
+ console.log("ajax失败了")
+ }
+ }
+ xhr.send({para1: para1})
+```
+
+### vue-resource
+https://github.com/pagekit/vue-resource
+```
+// global Vue object
+Vue.http.post('/someUrl', [body], {
+ headers: {"Content-type", "application/x-www-form-urlencoded"}
+}).then(successCallback, errorCallback);
+```
+
+### fetch
+https://github.com/github/fetch
+```
+fetch('/users', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({
+ name: 'Hubot',
+ login: 'hubot',
+ })
+}).then(function(response) {
+ // response.text()
+}).then(function(body) {
+ // body
+})
+
+// 文件上传
+var input = document.querySelector('input[type="file"]')
+
+var data = new FormData()
+data.append('file', input.files[0])
+data.append('user', 'hubot')
+
+fetch('/avatars', {
+ method: 'POST',
+ body: data
+})
+```
+
+### superagent
+https://github.com/visionmedia/superagent
+```
+request.post('/user')
+ .set('Content-Type', 'application/json')
+ .send('{"name":"tj","pet":"tobi"}')
+ .end(callback)
+```
+
+在React中可以将上述任意方法其置于componentDidMount()中,Vue.js同理。
+
+## 彻底移除ESlint方法
+删除package.json的devDependencies中所有eslint开头的插件,根目录下的“.eslintignore、.eslintrc.js”文件,并且修改package.json的dev为:
+```
+"dev": "gulp start"
+```
+删除gulpfile.js中的lint、eslint_start两个任务,并且把default改为“gulp.task('default', ['start']”。
diff --git a/build/dev-server.js b/build/dev-server.js
new file mode 100644
index 0000000..085b34e
--- /dev/null
+++ b/build/dev-server.js
@@ -0,0 +1,2 @@
+require("babel-register")
+require("../src/app")
diff --git a/config/main.js b/config/main.js
new file mode 100644
index 0000000..e69de29
diff --git a/gulpfile.js b/gulpfile.js
new file mode 100644
index 0000000..85dee3f
--- /dev/null
+++ b/gulpfile.js
@@ -0,0 +1,66 @@
+const gulp = require('gulp')
+const eslint = require('gulp-eslint')
+const nodemon = require('gulp-nodemon')
+const friendlyFormatter = require('eslint-friendly-formatter')
+
+var jsScript = 'node'
+if (process.env.npm_config_argv.indexOf('debug') > 0) {
+ jsScript = 'node debug'
+}
+
+gulp.task('lint', () => {
+ return gulp.src(['src/*.js', '!node_modules/**'])
+ .pipe(eslint({configFile: '.eslintrc.js'}))
+ .pipe(eslint.format(friendlyFormatter))
+ // .pipe(eslint.failAfterError())
+ .pipe(eslint.results(results => {
+ // Called once for all ESLint results.
+ console.log(`- Total Results: ${results.length}`)
+ console.log(`- Total Warnings: ${results.warningCount}`)
+ console.log(`- Total Errors: ${results.errorCount}`)
+ }))
+})
+
+gulp.task('eslint_start', ['lint'], function () {
+ var stream = nodemon({
+ script: 'build/dev-server.js',
+ execMap: {
+ js: jsScript
+ },
+ tasks: ['lint'],
+ verbose: true,
+ ignore: ['build/*.js', 'dist/*.js', 'nodemon.json', '.git', 'node_modules/**/node_modules', 'gulpfile.js'],
+ env: {
+ NODE_ENV: 'development'
+ },
+ ext: 'js json'
+ })
+
+ return stream
+ .on('restart', function () {
+ // console.log('Application has restarted!')
+ })
+ .on('crash', function () {
+ console.error('Application has crashed!\n')
+ // stream.emit('restart', 20) // restart the server in 20 seconds
+ })
+})
+
+gulp.task('start', function () {
+ return nodemon({
+ script: 'build/dev-server.js',
+ execMap: {
+ js: jsScript
+ },
+ verbose: true,
+ ignore: ['build/*.js', 'dist/*.js', 'nodemon.json', '.git', 'node_modules/**/node_modules', 'gulpfile.js'],
+ env: {
+ NODE_ENV: 'development'
+ },
+ ext: 'js json'
+ })
+})
+
+gulp.task('default', ['lint', 'eslint_start'], function () {
+ // console.log('ESlin检查完成')
+})
diff --git a/logs/out.log b/logs/out.log
new file mode 100644
index 0000000..9766475
--- /dev/null
+++ b/logs/out.log
@@ -0,0 +1 @@
+ok
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..aa693c6
--- /dev/null
+++ b/package.json
@@ -0,0 +1,35 @@
+{
+ "name": "koa2-API-scaffold",
+ "version": "1.0.0",
+ "description": "Koa2 RESTful API 服务器的脚手架",
+ "author": "轶哥 ",
+ "scripts": {
+ "start": "gulp start",
+ "dev": "gulp",
+ "build": "babel src -d dist",
+ "production": "node dist/app.js"
+ },
+ "dependencies": {
+ "koa": "^1.2.4"
+ },
+ "devDependencies": {
+ "babel-cli": "^6.22.2",
+ "babel-plugin-transform-runtime": "^6.22.0",
+ "babel-preset-es2015": "^6.22.0",
+ "babel-preset-stage-2": "^6.22.0",
+ "babel-register": "^6.22.0",
+ "eslint": "^3.14.0",
+ "eslint-config-standard": "^6.2.1",
+ "eslint-friendly-formatter": "^2.0.7",
+ "eslint-plugin-html": "^1.7.0",
+ "eslint-plugin-promise": "^3.4.0",
+ "eslint-plugin-standard": "^2.0.1",
+ "gulp": "^3.9.1",
+ "gulp-eslint": "^3.0.1",
+ "gulp-nodemon": "^2.2.1"
+ },
+ "engines": {
+ "node": ">= 6.9.4",
+ "npm": ">= 3.10.10"
+ }
+}
diff --git a/pm2.js b/pm2.js
new file mode 100644
index 0000000..7984191
--- /dev/null
+++ b/pm2.js
@@ -0,0 +1,17 @@
+module.exports = {
+ apps: [{
+ name: 'RESRful API Server',
+ script: './dist/app.js',
+ watch: false, // 默认关闭watch 可替换为 ['src']
+ ignore_watch: ['node_modules', 'build', 'logs'],
+ out_file: '/logs/out.log', // 日志输出
+ error_file: '/logs/error.log', // 错误日志
+ max_memory_restart: '2G', // 超过多大内存自动重启,仅防止内存泄露有意义,需要根据自己的业务设置
+ env: {
+ NODE_ENV: 'production'
+ },
+ exec_mode: 'cluster', // 开启多线程模式,用于负载均衡
+ instances: 'max', // 启用多少个实例,可用于负载均衡
+ autorestart: true // 程序崩溃后自动重启
+ }]
+}
diff --git a/src/app.js b/src/app.js
new file mode 100644
index 0000000..4ce04d0
--- /dev/null
+++ b/src/app.js
@@ -0,0 +1,3 @@
+
+console.log('ok')
+console.log('aaa')