Skip to content

Commit

Permalink
apibus v1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
michaellyu committed Apr 4, 2016
1 parent 35db49b commit 210015a
Show file tree
Hide file tree
Showing 12 changed files with 668 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
dist
**/*.swp
.DS_Store
65 changes: 65 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
## Api Bus
这是一个配合openresty完成的一个工具库,它包含了一个客户端脚本和一个服务端脚本程序。之所以给他命名为Api Bus,是因为它可以合并多个ajax请求到一个请求中,使api们就像是坐上了同一目的地的Bus,一起出发、一起到达。减少了页面连接数,并且得益于openresty的capture_multi子请求的特性,以达到多个请求只取最长响应时间为整体响应时间的特点,大幅提升页面加载速度。

## 快速开始
首先你需要一台安装了openresty的服务器(按照官网安装步骤很简单),将apibus.lua文件拷贝至项目的目录下,配置nginx中apibus的路由地址:
```
location /apis/apibus {
default_type "application/json; charset=utf-8";
content_by_lua_file apis/apibus.lua;
}
```

在页面中添加jQuery依赖,并引入apibus客户端
```html
<script src="//cdn.bootcss.com/jquery/1.12.0/jquery.min.js"></script>
<script src="/assets/lib/apibus.js"></script>
```

开始使用,将多个ajax请求加入到apibus队列中
```javascript
apiBus.add([{
url:'/apis/one',
success: function(result){
console.log('one api success!')
console.log(result);
},
complete: function(result){
console.log('one api complete!')
}
}, {

url:'/apis/two',
params: {arg: 'params?'},
success: function(result){
console.log('two api success!')
console.log(result);
}
}
]);

apiBus.add({
url:'/apis/three',
error: function(result){
console.log('three api error!')
console.log(result);
}
});

apiBus.add({
url:'/apis/four',
method: 'POST',
body: {d: 'ddd?'},
success: function(result){
console.log(result.data);
}
});

apiBus.start(function(){
console.log('api bus done!');
});
```

# License

MIT
60 changes: 60 additions & 0 deletions apibus.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
-- Api Bus for contact ajax requests
--
-- Author: Michael LYU <[email protected]>
--
-- Date: 2016-01-23
--
-- Version: 1.0.0

local cjson = require "cjson.safe";

ngx.req.read_body();
local post_args = ngx.req.get_post_args();
local bus = cjson.decode(post_args.apibus);

local methods = {
GET = ngx.HTTP_GET,
POST = ngx.HTTP_POST,
PUT = ngx.HTTP_PUT,
DELETE = ngx.HTTP_DELETE
};

local seats = {};
local seat;
local options;
for k, v in pairs(bus) do
seat = {v.url};
options = {};

if v.method then
options['method'] = methods[string.upper(v.method)];
end
if v.params then
options['args'] = v.params;
end
if v.body then
options['body'] = v.body;
end

if table.getn(options) then
table.insert(seat, 2, options);
end

table.insert(seats, k, seat);
end

local responses = {ngx.location.capture_multi(seats)};

local bus = {};
local res;
for k, v in pairs(responses) do
if v.status == 200 then
res = cjson.decode(v.body);
else
res = "error";
end

table.insert(bus, k, res);
end

ngx.say(cjson.encode(bus));
52 changes: 52 additions & 0 deletions demo/apis/apibus.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
local cjson = require "cjson.safe";

ngx.req.read_body();
local post_args = ngx.req.get_post_args();
local bus = cjson.decode(post_args.apibus);

local methods = {
GET = ngx.HTTP_GET,
POST = ngx.HTTP_POST,
PUT = ngx.HTTP_PUT,
DELETE = ngx.HTTP_DELETE
};

local seats = {};
local seat;
local options;
for k, v in pairs(bus) do
seat = {v.url};
options = {};

if v.method then
options['method'] = methods[string.upper(v.method)];
end
if v.params then
options['args'] = v.params;
end
if v.body then
options['body'] = v.body;
end

if table.getn(options) then
table.insert(seat, 2, options);
end

table.insert(seats, k, seat);
end

local responses = {ngx.location.capture_multi(seats)};

local bus = {};
local res;
for k, v in pairs(responses) do
if v.status == 200 then
res = cjson.decode(v.body);
else
res = "error";
end

table.insert(bus, k, res);
end

ngx.say(cjson.encode(bus));
45 changes: 45 additions & 0 deletions demo/conf/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
worker_processes 1;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
server {
listen 8080;
lua_code_cache off;
root ./public;
location /apis/apibus {
default_type "application/json; charset=utf-8";
content_by_lua_file apis/apibus.lua;
}
location /apis/one {
default_type application/json;
content_by_lua '
local cjson = require "cjson.safe";
ngx.say(cjson.encode({status = 1, data = {1, 2, 3}}));
';
}
location /apis/two {
default_type application/json;
content_by_lua '
local cjson = require "cjson.safe";
ngx.say(cjson.encode({status = 1, data = ngx.var.arg_arg}));
';
}
location /apis/three {
default_type application/json;
content_by_lua '
throw error;
';
}
location /apis/four {
default_type application/json;
content_by_lua '
local cjson = require "cjson.safe";
ngx.req.read_body();
local post_args = ngx.req.get_post_args();
ngx.say(cjson.encode({status = 1, data = post_args}));
';
}
}
}
144 changes: 144 additions & 0 deletions demo/public/assets/lib/apibus.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/*!
* Api Bus for contact ajax requests
*
* Author: Michael LYU <[email protected]>
*
* Date: 2016-01-23
*
* Version: 1.0.0
*/
(function(factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
define(['jquery'], function($) {
return factory($);
});
} else if (typeof exports !== 'undefined') {
module.exports = factory(require('jquery'));
} else {
factory(jQuery);
}
})(function($, undefined) {
'use strict';

var isUndefined = function (value) {return typeof value === 'undefined';}
var isObject = function (value){return value !== null && typeof value === 'object';};
var isFunction = function isFunction(value) {return typeof value === 'function';};
var isString = function isString(value) {return typeof value === 'string';}
var isArray = Array.isArray;

var getSeats = function (){
var seats = [];
for(var i = 0, len = bus.length; i < len; i++){
seats[i] = {url: bus[i].url};
isString(bus[i].method) && (seats[i].method = bus[i].method);
isString(bus[i].params) && (seats[i].url + (bus[i].url.indexOf('?') === -1 ? '?' : '&') + bus[i].params);
isObject(bus[i].params) && (seats[i].params = bus[i].params);
isString(bus[i].body) && (seats[i].body = bus[i].body);
isObject(bus[i].body) && (seats[i].body = $.param(bus[i].body));
}
return seats;
};

var bus = [],
seat,
xhr;

var config = {
way: '/apis/apibus',
name: 'apibus',
autoClear: true
};

var apiBus = function(seats){
if(isUndefined(seats)){
return;
}

isArray(seats) || (seats = [seats]);

for(var i = 0, len = seats.length; i < len; i++){
if(isObject(seats[i]) && isString(seats[i].url)){
seat = {};

seat.url = seats[i].url;
isString(seats[i].method) && (seat.method = seats[i].method);
(isObject(seats[i].params) || isString(seats[i].params)) && (seat.params = isString(seats[i].params) ? seats[i].params : seats[i].params);
isObject(seats[i].body) && (seat.body = seats[i].body);
isFunction(seats[i].success) && (seat.success = seats[i].success);
isFunction(seats[i].error) && (seat.error = seats[i].error);
isFunction(seats[i].complete) && (seat.complete = seats[i].complete);

bus.push(seat);
}
}
};

apiBus.config = function(options){
if(isUndefined(options)){
return config;
}

$.extend(config, options);
};

apiBus.add = function(seats){
apiBus(seats);
};

apiBus.start = function(callback){
if(bus.length === 0){
return;
}

var data = {};
data[config.name] = JSON.stringify(getSeats());
xhr = $.post(config.way + (config.way.indexOf('?') === -1 ? '?' : '&') + '&bust=' + new Date().getTime(), data)
.success(function(result){
if(isArray(result)){
for(var i = 0, len = bus.length; i < len; i++){
if(isString(result[i]) && result[i] === 'error' && isFunction(bus[i].error)){
bus[i].error(result[i]);
}
else if(isFunction(bus[i].success)){
bus[i].success(result[i]);
}
}
}
})
.error(function(){
for(var i = 0, len = bus.length; i < len; i++){
if(isFunction(bus[i].error)){
bus[i].error.apply(this, arguments);
}
}
})
.complete(function(result){
for(var i = bus.length - 1; i >= 0; i--){
if(isFunction(bus[i].complete)){
bus[i].complete(result[i]);
}
}

if(config.autoClear){
apiBus.clear();
}

if(isFunction(callback)){
callback();
}
});
};

apiBus.stop = function(){
if(xhr){
xhr.abort();
}
};

apiBus.clear = function(){
bus.length = 0;
};

window.apiBus = $.apiBus = apiBus;
});
Loading

0 comments on commit 210015a

Please sign in to comment.