Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
node_modules
bower_components
demo/config.js
demo/deploy.sh
deploy.sh
14 changes: 6 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ Qiniu-JavaScript-SDK 的示例 Demo 中的服务器端部分是基于[ Node.js
- 在使用 JS-SDK 之前,您必须先注册一个七牛帐号,并登录控制台获取一对有效的 AccessKey 和 SecretKey,您可以阅读[ 快速入门 ](https://developer.qiniu.com/kodo/manual/console-quickstart)和[ 安全机制 ](https://developer.qiniu.com/kodo/manual/security#security) 以进一步了解如何正确使用和管理密钥 。

- JS-SDK 依赖服务端颁发 uptoken,可以通过以下二种方式实现:
- 利用[七牛服务端 SDK ](https://developer.qiniu.com/sdk#sdk)构建后端服务
- 利用[七牛服务端 SDK ](https://developer.qiniu.com/sdk#sdk)构建后端服务
- 利用七牛底层 API 构建服务,详见七牛[上传策略](https://developer.qiniu.com/kodo/manual/put-policy)和[上传凭证](https://developer.qiniu.com/kodo/manual/upload-token)

后端服务应提供一个 URL 地址,供 JS-SDK 初始化使用,前端通过 Ajax 请求该地址后获得 uptoken。Ajax 请求成功后,服务端应返回如下格式的 json:
Expand Down Expand Up @@ -197,7 +197,7 @@ Qiniu-JavaScript-SDK 的示例 Demo 中的服务器端部分是基于[ Node.js
// downtoken_url: '/downtoken',
// Ajax请求downToken的Url,私有空间时使用,JS-SDK 将向该地址POST文件的key和domain,服务端返回的JSON必须包含`url`字段,`url`值为该文件的下载地址
// unique_names: true, // 默认 false,key 为文件名。若开启该选项,JS-SDK 会为每个文件自动生成key(文件名)
// save_key: true, // 默认 false。若在服务端生成 uptoken 的上传策略中指定了 `sava_key`,则开启,SDK在前端将不对key进行任何处理
// save_key: true, // 默认 false。若在服务端生成 uptoken 的上传策略中指定了 `save_key`,则开启,SDK在前端将不对key进行任何处理
domain: '<Your bucket domain>', // bucket 域名,下载资源时用到,如:'http://xxx.bkt.clouddn.com/' **必需**
container: 'container', // 上传区域 DOM ID,默认是 browser_button 的父元素,
max_file_size: '100mb', // 最大文件体积限制
Expand Down Expand Up @@ -789,7 +789,7 @@ $(function() {

<a class="btn btn-default btn-lg " id="up_load" style="width:160px" href="#" >
<span>确认上传</span>
</a>
</a>

<a class="btn btn-default btn-lg " id="stop_load" style="width:160px" href="#" >
<span>暂停上传</span>
Expand All @@ -804,7 +804,7 @@ $(function() {

<a class="btn btn-default btn-lg " id="up_load2" style="width:160px" href="#" >
<span>确认上传</span>
</a>
</a>

<a class="btn btn-default btn-lg " id="stop_load2" style="width:160px" href="#" >
<span>暂停上传</span>
Expand All @@ -830,8 +830,6 @@ $(function() {
<a id="license"></a>
### 许可证

> Copyright (c) 2014 qiniu.com

### 基于 GPL V2 协议发布:
> Copyright (c) 2017 qiniu.com

> [www.gnu.org/licenses/gpl-2.0.html](http://www.gnu.org/licenses/gpl-2.0.html)
### 基于 MIT 协议发布
15 changes: 11 additions & 4 deletions bower.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
{
"name": "qiniu",
"description": "Javascript SDK for Qiniu Resource (Cloud) Storage API",
"version": "v1.0.14-beta",
"version": "v1.0.19",
"main": "dist/qiniu.js",
"moduleType": ["globals"],
"license": "GPL V2",
"moduleType": [
"globals"
],
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
Expand All @@ -21,6 +23,10 @@
],
"authors": "sdk@qiniu.com",
"contributors": [
{
"name": "luoyeshu0507",
"email": "lizhiwei@qiniu.com"
},
{
"name": "codedogfish",
"email": "jackyu@qiniu.com"
Expand All @@ -42,7 +48,8 @@
"bootstrap": "~3.3.6",
"highlight": "~8.9.1",
"jquery": "~1.9.1",
"respond": "~1.4.2"
"respond": "~1.4.2",
"vue": "^2.2.1"
},
"private": false
}
60 changes: 60 additions & 0 deletions demo/scripts/http-performance.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* @license httpPerformance v1.0.0
* License: MIT
* author: luoyeshu0507
*
* @description
*
* This object provides a utility for detailing the http request performance
*
*/
;(function(window, undefined){
'use strict';
var p = window.performance;
var httpPerformance = {
clear: function() {
p.clearMarks();
p.clearMeasures();
p.clearResourceTimings();
},
getAll: function() {
var performanceArr = [];
p.getEntries().forEach(function(item) {
performanceArr.push(httpPerformance.formatPerformance(item));
});
return performanceArr;
},
getByName: function(name) {
var performanceArr = [];
p.getEntriesByName(name).forEach(function(item) {
performanceArr.push(httpPerformance.formatPerformance(item));
});
return performanceArr;
},
formatPerformance: function(prt) { // PerformanceResourceTiming
return {
redirect: prt.redirectEnd - prt.redirectStart,
domainLookup: prt.domainLookupEnd - prt.domainLookupStart,
connect: prt.connectEnd - prt.connectStart,
request: prt.responseStart - prt.requestStart,
response: prt.responseEnd - prt.responseStart,

entryType: prt.entryType,
initiatorType: prt.initiatorType,
name: prt.name,
duration: prt.duration,
};
}
};

// support AMD and CMD
if (typeof module !== 'undefined' && module.exports) {
module.exports = httpPerformance;
} else if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {
define('httpPerformance', [], function () {
return httpPerformance;
});
} else {
window.httpPerformance = httpPerformance;
}
})(window);
188 changes: 188 additions & 0 deletions demo/scripts/performance.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
Vue.component('zone-list', {
props: ['hostMap', 'currentZone', 'switchZone', 'selectedHost'],
template: '<div class="uphosts-list"><ul><li v-for="item in hostMap" :class="{on: item.zone == currentZone}" @click="switchZone(item.zone)">{{item.zoneZh}}</li></ul><ul><li v-for="item in hostMap" :class="{on: item.zone == currentZone}"><label v-for="uphost in item.uphosts"><input type="radio" v-model="selectedHost.host" :value="uphost"/>{{uphost}}</label></li></ul></div>'
});
Vue.component('upload-performance', {
props: ['per'],
template: '<div class="up-performance"><div class="per-title">上传耗时:</div>' +
'<table>' +
'<tr><th>类型</th><th>耗时 / ms</th></tr>' +
'<tr><td>重定向:</td><td>{{per.redirect | tofixed(2)}}</td></tr>' +
'<tr><td>DNS 查询:</td><td>{{per.domainLookup | tofixed(2)}}</td></tr>' +
'<tr><td>建立连接:</td><td>{{per.connect | tofixed(2)}}</td></tr>' +
'<tr><td>发送数据到开始响应:</td><td>{{per.request | tofixed(2)}}</td></tr>' +
'<tr><td>接收响应:</td><td>{{per.response | tofixed(2)}}</td></tr>' +
'<tr><td>总耗时:</td><td>{{per.duration | tofixed(2)}}</td></tr></table>' +
'</div>'
});
Vue.component('up-headers', {
props: ['headers'],
template: '<div class="up-headers"><div class="per-title">响应头:</div><table><tr><th>类型</th><th>值</th></tr><tr v-for="header in headers"><td>{{header.key}}</td><td>{{header.val}}</td></tr></table></div>'
});
Vue.filter('tofixed', function (val, size) {
return val.toFixed(size);
});

var app = new Vue({
el: '#app',
data: {
currentZone: 'z0',
selectedHost: {
host: ''
},
currentToken: '',
loadMessage: '',
hostMap: [
{
zone: 'z0',
zoneZh: '华东',
token: 'xozWSPMxkMjIVoHg2JyXq4-7-oJaEADLOKHVR0vU:hzD116IsDOpb4gjzyPg7ngg4Qjs=:eyJzY29wZSI6Impzc2RrOmEuanBnIiwiZGVhZGxpbmUiOjIxMTQzODA4MDAwMDAsImZzaXplTGltaXQiOjEwMDAwMDB9',
uphosts: [
'http://up.qiniu.com',
'http://upload.qiniu.com',
'https://up.qbox.me',
'https://upload.qbox.me'
]
},
{
zone: 'z1',
zoneZh: '华北',
token: 'xozWSPMxkMjIVoHg2JyXq4-7-oJaEADLOKHVR0vU:9RFuA13c6pp-O2aIOe1UfTI3rlo=:eyJzY29wZSI6Impzc2RrLXoxOmEuanBnIiwiZGVhZGxpbmUiOjIxMTQzODA4MDAwMDAsImZzaXplTGltaXQiOjEwMDAwMDB9',
uphosts: [
'http://up-z1.qiniu.com',
'http://upload-z1.qiniu.com',
'https://up-z1.qbox.me',
'https://upload-z1.qbox.me'
]
},
{
zone: 'z2',
zoneZh: '华南',
token: 'xozWSPMxkMjIVoHg2JyXq4-7-oJaEADLOKHVR0vU:qmDBxiYviu0tg2hZzCFHjCZM3-w=:eyJzY29wZSI6Impzc2RrLXoyOmEuanBnIiwiZGVhZGxpbmUiOjIxMTQzODA4MDAwMDAsImZzaXplTGltaXQiOjEwMDAwMDB9',
uphosts: [
'http://up-z2.qiniu.com',
'http://upload-z2.qiniu.com',
'https://up-z2.qbox.me',
'https://upload-z2.qbox.me'
]
},
{
zone: 'na0',
zoneZh: '北美',
token: 'xozWSPMxkMjIVoHg2JyXq4-7-oJaEADLOKHVR0vU:DMPzTGGhX3HY0ph99YfAK_y-0XM=:eyJzY29wZSI6Impzc2RrLW5hMDphLmpwZyIsImRlYWRsaW5lIjoyMTE0MzgwODAwMDAwLCJmc2l6ZUxpbWl0IjoxMDAwMDAwfQ==',
uphosts: [
'http://up-na0.qiniu.com',
'http://upload-na0.qiniu.com',
'https://up-na0.qbox.me',
'https://upload-na0.qbox.me'
]
},
],
isPerformanceSupported: true,
performance: null,
headers: null
},
methods: {
renderHtml: function() {},
post: function(opt) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.open('POST', opt.url, true);
xmlHttp.setRequestHeader('X-Qiniu-Performance', 'true');
xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState == 4) {
if (xmlHttp.status == 200) {
opt.success(xmlHttp);
} else {
opt.error(xmlHttp.responseText);
}
}
};
xmlHttp.upload.onprogress = opt.progress;
xmlHttp.send(opt.data);
},
uploadTest: function() {
if(!this.selectedHost.host) return;
this.resetResult();
var self = this;
this.post({
url: this.selectedHost.host,
data: this.mockDate(),
progress: function(e) {
if (e.lengthComputable) {
var percent = e.loaded/e.total*100;
self.loadMessage = '模拟数据上传:' + e.loaded + " / " + e.total+" bytes 完成:" + percent.toFixed(2) + "%";
}
},
success: function(xhr) {
self.formateHeader(xhr.getAllResponseHeaders());
self.getPerformance();
},
error: function(res) {
self.loadMessage = '上传失败:' + res;
}
});
},
mockDate: function(size) {
var f = new FormData(document.getElementById("testform"));
f.append('file', this.dataURLtoBlob(this.randomBase64(size)));
f.append('token', this.currentToken);
return f;
},
randomBase64: function() {
var dataurl = 'data:image/jpeg;base64,';
var len = parseInt(Math.random()*(1330000-1100000+1)+1100000, 10);
while (dataurl.length < len) {
dataurl += Math.random > 0.5 ? '/9j/4AAQSkZJRgABAQAASABIAAD/4Q' : '/9j/4AAQSkZJRgABAQAASABIAAD/4W';
}
return dataurl;
},
dataURLtoBlob: function(dataurl) {
var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], {type:mime});
},
resetResult: function() {
for (var i = 0; i < this.hostMap.length; i++) {
if (this.hostMap[i].zone === this.currentZone) {
this.currentToken = this.hostMap[i].token;
break;
}
}
this.performance = null;
this.headers = null;
},
switchZone: function(zone) {
this.currentZone = zone;
this.selectedHost.host = '';
},
getPerformance: function() {
var per = httpPerformance.getByName(this.selectedHost.host + '/');
if(per.length == 2) {
per[1].redirect = per[0].redirect;
per[1].domainLookup = per[0].domainLookup;
per[1].connect = per[0].connect;
}
this.performance = per[1] || per[0]; // 跨域有时候会先发送一个 option 请求,并不是真的上传请求。
},
formateHeader: function(headers) {
var list = [];
headers.match(/.+/mg).map(function(item) {
var index = item.indexOf(':');
var o = {
key: item.substr(0, index),
val: item.substr(index + 1)
};
list.push(o);
});
this.headers = list;
}
},
created: function() {
this.isPerformanceSupported = !!(window.performance && window.performance.getEntries);
}
});


8 changes: 8 additions & 0 deletions demo/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ app.get('/formdata', function(req, res) {
});
});

app.get('/performance', function(req, res) {
var token = uptoken.token();
res.render('performance.html', {
uptoken: token
});
});

qiniu.conf.ACCESS_KEY = config.ACCESS_KEY;
qiniu.conf.SECRET_KEY = config.SECRET_KEY;

Expand All @@ -95,5 +102,6 @@ app.listen(config.Port, function() {
console.log(' ▹▹▹▹▹▹▹▹▹▹▹▹▹▹▹▹ Upload: http://127.0.0.1:%d ◁ ◁ ◁ ◁ ◁ ◁ ◁', config.Port);
console.log(' ▹▹▹▹▹▹▹ Multiple upload: http://127.0.0.1:%d/multiple ◁ ◁ ◁', config.Port);
console.log(' ▹▹▹▹▹▹▹ Formdata upload: http://127.0.0.1:%d/formdata ◁ ◁ ◁', config.Port);
console.log(' ▹▹▹▹▹▹▹ Up Performance: http://127.0.0.1:%d/performance ◁ ◁', config.Port);
console.log('△ △ △ △ △ △ △ △ △ △ △ △ △ △ △ △ △ △ △ △ △ △ △ △ △ △ △ △ △ △ △ △ △\n');
});
Loading