aliyun-api-gateway
Advanced tools
Comparing version 1.0.3 to 1.0.4
11
index.js
@@ -6,1 +6,12 @@ 'use strict'; | ||
exports.SimpleClient = require('./lib/simple-client'); | ||
//表单类型Content-Type | ||
exports.CONTENT_TYPE_FORM = 'application/x-www-form-urlencoded; charset=UTF-8'; | ||
// 流类型Content-Type | ||
exports.CONTENT_TYPE_STREAM = 'application/octet-stream; charset=UTF-8'; | ||
//JSON类型Content-Type | ||
exports.CONTENT_TYPE_JSON = 'application/json; charset=UTF-8'; | ||
//XML类型Content-Type | ||
exports.CONTENT_TYPE_XML = 'application/xml; charset=UTF-8'; | ||
//文本类型Content-Type | ||
exports.CONTENT_TYPE_TEXT = 'application/text; charset=UTF-8'; |
@@ -6,2 +6,15 @@ 'use strict'; | ||
function loweredKeys(headers = {}) { | ||
var lowered = {}; | ||
var keys = Object.keys(headers); | ||
for (let i = 0; i < keys.length; i++) { | ||
let key = keys[i]; | ||
lowered[key.toLowerCase()] = headers[key]; | ||
} | ||
return lowered; | ||
} | ||
/** | ||
@@ -11,23 +24,75 @@ * API Gateway Client | ||
class Base { | ||
constructor() { | ||
} | ||
constructor() {} | ||
* get(url, opts) { | ||
opts || (opts = {}); | ||
* get(url, opts = {}) { | ||
var parsed = parse(url, true); | ||
if (opts && opts.data) { | ||
var maybeQuery = opts.query || opts.data; | ||
if (maybeQuery) { | ||
// append data into querystring | ||
Object.assign(parsed.query, opts.data); | ||
Object.assign(parsed.query, maybeQuery); | ||
parsed.path = parsed.pathname + '?' + querystring.stringify(parsed.query); | ||
opts.data = null; | ||
opts.query = null; | ||
} | ||
// lowerify the header key | ||
opts.headers = loweredKeys(opts.headers); | ||
opts.signHeaders = loweredKeys(opts.signHeaders); | ||
return yield* this.request('GET', parsed, opts); | ||
} | ||
* post(url, opts) { | ||
opts.data = JSON.stringify(opts.data); | ||
return yield* this.request('POST', url, opts); | ||
* post(url, opts = {}) { | ||
var parsed = parse(url, true); | ||
var query = opts.query; | ||
if (query) { | ||
// append data into querystring | ||
Object.assign(parsed.query, query); | ||
parsed.path = parsed.pathname + '?' + querystring.stringify(parsed.query); | ||
opts.query = null; | ||
} | ||
// lowerify the header key | ||
opts.headers = loweredKeys(opts.headers); | ||
opts.signHeaders = loweredKeys(opts.signHeaders); | ||
var headers = opts.headers; | ||
var type = headers['content-type'] || headers['Content-Type']; | ||
if (!type) { | ||
headers['content-type'] = 'application/json'; | ||
type = headers['content-type']; | ||
} | ||
var originData = opts.data; | ||
if (type.startsWith('application/x-www-form-urlencoded')) { | ||
opts.data = querystring.stringify(opts.data); | ||
} else if (type.startsWith('application/json')) { | ||
opts.data = JSON.stringify(opts.data); | ||
} else if (!Buffer.isBuffer(opts.data) && typeof opts.data !== 'string') { | ||
// 非buffer和字符串时,以JSON.stringify()序列化 | ||
opts.data = JSON.stringify(opts.data); | ||
} | ||
return yield* this.request('POST', url, opts, originData); | ||
} | ||
* delete(url, opts) { | ||
var parsed = parse(url, true); | ||
var maybeQuery = opts.query || opts.data; | ||
if (maybeQuery) { | ||
// append data into querystring | ||
Object.assign(parsed.query, maybeQuery); | ||
parsed.path = parsed.pathname + '?' + querystring.stringify(parsed.query); | ||
opts.data = null; | ||
opts.query = null; | ||
} | ||
// lowerify the header key | ||
opts.headers = loweredKeys(opts.headers); | ||
opts.signHeaders = loweredKeys(opts.signHeaders); | ||
return yield* this.request('DELETE', parsed, opts); | ||
} | ||
} | ||
module.exports = Base; |
@@ -13,2 +13,7 @@ 'use strict'; | ||
const form = 'application/x-www-form-urlencoded'; | ||
const hasOwnProperty = function (obj, key) { | ||
return Object.prototype.hasOwnProperty.call(obj, key); | ||
}; | ||
/** | ||
@@ -18,10 +23,10 @@ * API Gateway Client | ||
class Client extends Base { | ||
constructor(key, secret, stage) { | ||
constructor(key, secret, stage = 'RELEASE') { | ||
super(); | ||
this.appKey = key; | ||
this.appSecret = Buffer.from(secret, 'utf8'); | ||
this.stage = stage || 'RELEASE'; | ||
this.stage = stage; | ||
} | ||
buildStringToSign(method, headers, signedHeadersStr, url) { | ||
buildStringToSign(method, headers, signedHeadersStr, url, data) { | ||
// accept, contentMD5, contentType, | ||
@@ -60,3 +65,7 @@ const lf = '\n'; | ||
list.push(this.buildUrl(url)); | ||
if (method === 'POST' && contentType.startsWith(form)) { | ||
list.push(this.buildUrl(url, data)); | ||
} else { | ||
list.push(this.buildUrl(url)); | ||
} | ||
@@ -77,3 +86,3 @@ return list.join(''); | ||
getSignHeaders(headers) { | ||
getSignHeaderKeys(headers, signHeaders) { | ||
var keys = Object.keys(headers).sort(); | ||
@@ -83,3 +92,4 @@ var signKeys = []; | ||
var key = keys[i]; | ||
if (key.toLowerCase().startsWith('x-ca-')) { | ||
// x-ca- 开头的header或者指定的header | ||
if (key.startsWith('x-ca-') || hasOwnProperty(signHeaders, key)) { | ||
signKeys.push(key); | ||
@@ -89,7 +99,8 @@ } | ||
return signKeys; | ||
// 按字典序排序 | ||
return signKeys.sort(); | ||
} | ||
buildUrl(parsedUrl) { | ||
var toStringify = parsedUrl.query; | ||
buildUrl(parsedUrl, data) { | ||
var toStringify = Object.assign(parsedUrl.query, data); | ||
var result = parsedUrl.pathname; | ||
@@ -101,3 +112,7 @@ if (Object.keys(toStringify).length) { | ||
var key = keys[i]; | ||
list[i] = `${key}=${toStringify[key]}`; | ||
if (toStringify[key] && ('' + toStringify[key])) { | ||
list[i] = `${key}=${toStringify[key]}`; | ||
} else { | ||
list[i] = `${key}`; | ||
} | ||
} | ||
@@ -109,20 +124,10 @@ result += '?' + list.join('&'); | ||
buildHeaders(headers) { | ||
var now = new Date(); | ||
var keys = Object.keys(headers || {}); | ||
var lowered = {}; | ||
for (var i = 0; i < keys.length; i++) { | ||
var key = keys[i]; | ||
lowered[key.toLowerCase()] = headers[key]; | ||
} | ||
buildHeaders(headers = {}, signHeaders) { | ||
return Object.assign({ | ||
'x-ca-timestamp': now.getTime(), | ||
'x-ca-timestamp': Date.now(), | ||
'x-ca-key': this.appKey, | ||
'x-ca-nonce': uuid.v4(), | ||
'x-ca-stage': this.stage, | ||
'content-type': 'application/json', | ||
'accept': 'application/json' | ||
}, lowered); | ||
}, headers, signHeaders); | ||
} | ||
@@ -140,15 +145,18 @@ | ||
* request(method, url, opts) { | ||
var headers = this.buildHeaders(opts.headers); | ||
* request(method, url, opts, originData) { | ||
var signHeaders = opts.signHeaders; | ||
// 小写化,合并之后的headers | ||
var headers = this.buildHeaders(opts.headers, signHeaders); | ||
if (method === 'POST' && headers['content-type'] === 'application/octet-stream') { | ||
var requestContentType = headers['content-type']; | ||
if (method === 'POST' && !requestContentType.startsWith(form)) { | ||
headers['content-md5'] = this.md5(opts.data); | ||
} | ||
var signHeaders = this.getSignHeaders(headers); | ||
headers['x-ca-signature-headers'] = signHeaders.join(','); | ||
var signedHeadersStr = this.getSignedHeadersString(signHeaders, headers); | ||
var signHeaderKeys = this.getSignHeaderKeys(headers, signHeaders); | ||
headers['x-ca-signature-headers'] = signHeaderKeys.join(','); | ||
var signedHeadersStr = this.getSignedHeadersString(signHeaderKeys, headers); | ||
var parsedUrl = parse(url, true); | ||
var stringToSign = this.buildStringToSign(method, headers, signedHeadersStr, parsedUrl); | ||
var stringToSign = this.buildStringToSign(method, headers, signedHeadersStr, parsedUrl, originData); | ||
headers['x-ca-signature'] = this.sign(stringToSign); | ||
@@ -187,3 +195,3 @@ headers['user-agent'] = ua; | ||
var contentType = response.headers['content-type'] || ''; | ||
if (contentType.includes('application/json')) { | ||
if (contentType.startsWith('application/json')) { | ||
result = JSON.parse(result); | ||
@@ -190,0 +198,0 @@ } |
{ | ||
"name": "aliyun-api-gateway", | ||
"version": "1.0.3", | ||
"version": "1.0.4", | ||
"description": "Aliyun API Gateway Node.js SDK", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
12872
309