react-native-qiniu源码修改(实现文件上传,上传策略等)
2017-12-11 19:25
477 查看
react-native 对七牛的扩展支持
问题:react-native-qiniu 已经废弃好久了,没有人写,网上找到的也只能解决一点点问题,然后图片上传也存在着一系列的问题.参考着网上一些代码,我修改了其文件上传的部分.虽然可以在服务端进行上传,但总觉得base64先上传到服务器,再通过服务器上传到网站的话,在图片很多的情况下会影响一些性能,而且也不是很方便
修改后:
1. 可以上传文件,自定义参数上传,在上传成功后可以正确获取到参数信息, token会正确生成
2. 可以指定上传策略 如:returnbody等
3. 错误时可以收到错误信息
4. 增加进度显示,可以获取上传文件的进度
5. 添加了回调函数,可以监听xmlhttprequest的readystate(没什么用)
注:
1. 原七牛网址:https://github.com/qiniudemo/react-native-sdk
使用步骤:
1. 下载原react-native-qiniu * npm i react-native-qiniu –save *
2. 替换目录里的两个文件* rpc.js*和* auth.js*
3. 使用修改后API进行上传
如果是和我一样不知道如何使用七牛上传的小白可以参看以下官方文档:
1. 上传策略部分: https://developer.qiniu.com/kodo/manual/1206/put-policy
2. 直传文件部分:https://developer.qiniu.com/kodo/api/1312/upload
(react native实际上是使用formData 模拟表单来进行文件的上传)
如有其他问题欢迎留言,互相讨论进步
修改的代码部分
* rpc.js*主要修改部分:
uploadFile函数重构
添加回调
处理promise
import conf from './conf.js'; import Auth from './auth'; //发送管理和fop命令,总之就是不上传文件 function post(uri, adminToken, content) { var headers = { 'Content-Type': 'application/x-www-form-urlencoded', }; let payload = { headers: headers, method: 'POST', dataType: 'json', timeout: conf.RPC_TIMEOUT, }; if (typeof content === 'undefined') { payload.headers['Content-Length'] = 0; } else { //carry data payload.body = content; } if (adminToken) { headers['Authorization'] = adminToken; } return fetch(uri, payload); } /** * 直传文件 * formInput对象如何配置请参考七牛官方文档“直传文件”一节 */ function uploadFile(dataParams, policy, callbackUpDate = function () { }, callBackMethod = function () { }) { let params = getParams(dataParams, policy); let uri = params.uri; let data = params.data; let oloaded = null; let responseObj = {}; return new Promise((resolve, reject) => { if (typeof uri != 'string' || uri == '' || typeof data.key == 'undefined') { reject && reject(null); return; } if (uri[0] == '/') { uri = "file://" + uri; } //创建xhr并open var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { responseObj.readyState = xhr.readyState; //状态0-4 responseObj.data = xhr.response;//返回值 responseObj.textData = xhr.responseText; //返回值Text responseObj.status = xhr.status; //状态码 // responseObj.message = "" switch (xhr.readyState) { case 0: callBackMethod(responseObj) break; case 1: callBackMethod(responseObj) break; case 2: callBackMethod(responseObj) break; case 3: callBackMethod(responseObj) break; case 4: if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) { if (xhr.status == 200) { callBackMethod(responseObj) } } else { callBackMethod(responseObj) } break; } }; xhr.open('POST', conf.UP_HOST); xhr.onload = () => { if (xhr.status !== 200) { reject && reject(responseObj); return; } resolve && resolve(JSON.parse(responseObj.data)); }; xhr.onerror = (evt) => { reject && reject(evt); return; }; //请求失败 xhr.upload.onloadstart = () => {//上传开始执行方法 oloaded = 0;//设置上传开始时,以上传的文件大小为0 console("上传开始") }; xhr.upload.onprogress = (evt) => { oloaded = evt.loaded;//重新赋值已上传文件大小,用以下次计算 callbackUpDate(Math.round(oloaded / evt.total * 100), oloaded, evt.total) }; xhr.upload.onloadend = (evt) => { console("上传结束") }; let formdata = creatFormData(params); xhr.send(formdata); }); } //构造上传参数 function getParams(data, policy) { let putPolicy = new Auth.Policy( policy ); let uptoken = putPolicy.token(); data.token = uptoken; let params = {}; params.uri = data.uri; delete data.uri; params.data = data; return params; } /** * 创建一个表单对象,用于上传参数 * @param {*} params */ function creatFormData(params) { let formdata = new FormData(); let uri = params.uri; let formInput = creatFormInput(uri); let data = params.data; console.log(data) for (let key of Object.keys(data)) { let value = data[key]; if (key.charAt(0) === "_") { formdata.append("x:" + key.substring(1, key.length), value); } else { formdata.append(key, value); } } formdata.append("file", { uri: uri, type: formInput.type, name: formInput.name }); console.log(formdata) return formdata; } /** * 构造表单对象中file对象 * @param {*} params */ function creatFormInput(uri) { let formInput = {}; if (typeof formInput.type == 'undefined') formInput.type = 'application/octet-stream'; if (typeof formInput.name == 'undefined') { var filePath = uri.split("/"); if (filePath.length > 0) formInput.name = filePath[filePath.length - 1]; else formInput.name = ""; } return formInput; } export default { uploadFile, post }
* auth.js* (貌似模板字符串在这里会影响代码高亮)
主要修改部分:
PutPolicy类重构为Policy类
修改构造JSON字符串算法 _parse2Str()
import base64 from 'base-64'; import CryptoJS from "crypto-js"; import conf from "./conf.js"; import parse from 'url-parse'; function urlsafeBase64Encode(jsonFlags) { var encoded = base64.encode(jsonFlags); return base64ToUrlSafe(encoded); }; function base64ToUrlSafe(v) { return v.replace(/\//g, '_').replace(/\+/g, '-'); }; function hmacSha1(encodedFlags, secretKey) { var encoded = CryptoJS.HmacSHA1(encodedFlags, secretKey).toString(CryptoJS.enc.Base64); return encoded; }; function generateAccessToken(url, body) { var u = parse(url, true); var path = u.pathname; var access = path + '\n'; if (body) { access += body; } var digest = hmacSha1(access, conf.SECRET_KEY); var safeDigest = base64ToUrlSafe(digest); let token = 'QBox ' + conf.ACCESS_KEY + ':' + safeDigest; //console.log(token); return token; }; class Policy { constructor(policy) { if (typeof (policy) == "undefined") { } else { this.policy = policy; if (typeof (policy.deadline) == "undefined" || policy.deadline == null) { this.policy.deadline = 3600 + Math.floor(Date.now() / 1000); } } } _parse2Str(putPolicy) { let str = "{"; let keys = Object.keys(putPolicy); keys.forEach((key, i) => { let value = putPolicy[key]; if (typeof (value) == "object") { str = `${str}"${key}":` str = `${str}"{` Object.keys(value).forEach((key2) => { let value2 = value[key2]; let re = /(\$\(.*?\))/g; if(re.test(value2)){ str = `${str}\\\"${key2}\\\":${value2},` }else{ str = `${str}\\\"${key2}\\\":"${value2}",` } }) console.log(keys.length + "::" + i) if (i >= keys.length) { str = `${str.substring(0, str.length - 1)}}"` }else{ str = `${str.substring(0, str.length - 1)}}",` } } else if (typeof (value) == "number") { str = `${str}"${key}":${value},` } else if (typeof (value) == "string") { str = `${str}"${key}":"${value}",` } else { str = `${str}"${key}":"${value}",` } }) str = `${str.substring(0, str.length - 1)}}`; return str; } // _creatStr = (policy) => { // policy['deadline'] = this.expires + Math.floor(Date.now() / 1000); // let policyStr = JSON.stringify(policy); // let re = /(\"\$\(.*?\)\")/g; // let newStr = policyStr.replace(re, (value) => { // return value.substring(1, value.length - 1); // }) // return newStr; // } token = () => { policStr = this._parse2Str(this.policy); console.log("policStr", policStr); var encodedPutPolicy = this._urlsafeBase64Encode(policStr); console.log("encodedPutPolicy", encodedPutPolicy); var sign = this._hmacSha1(encodedPutPolicy, conf.SECRET_KEY); var encodedSign = this._base64ToUrlSafe(sign); console.log("encodedSign", encodedSign); var uploadToken = conf.ACCESS_KEY + ':' + encodedSign + ':' + encodedPutPolicy; console.log("uploadToken", uploadToken); return uploadToken; } _urlsafeBase64Encode = (jsonFlags) => { var encoded = base64.encode(jsonFlags); return base64ToUrlSafe(encoded); }; _base64ToUrlSafe = (v) => { return v.replace(/\//g, '_').replace(/\+/g, '-'); }; _hmacSha1 = (encodedFlags, secretKey) => { var encoded = CryptoJS.HmacSHA1(encodedFlags, secretKey).toString(CryptoJS.enc.Base64); return encoded; }; } class GetPolicy { constructor(expires) { this.expires = expires || 3600; } makeRequest(baseUrl) { var deadline = this.expires + Math.floor(Date.now() / 1000); if (baseUrl.indexOf('?') >= 0) { baseUrl += '&e='; } else { baseUrl += '?e='; } baseUrl += deadline; var signature = hmacSha1(baseUrl, conf.SECRET_KEY); var encodedSign = base64ToUrlSafe(signature); var downloadToken = conf.ACCESS_KEY + ':' + encodedSign; return baseUrl + '&token=' + downloadToken; } } export default { urlsafeBase64Encode, generateAccessToken, Policy, GetPolicy }
使用方法部分
自定义参数使用 _ 开头值全部为字符串形式,如”${fname}”
import Qiniu, { Auth, ImgOps, Conf, Rs, Rpc } from 'react-native-qiniu';//添加七牛引用 Conf.ACCESS_KEY = "DT66l5FkxNivhSD0zJKjXr_WccNtZwS4cppxlIzy"; Conf.SECRET_KEY = "jb8s3PfQVCRzp_LYG33_QHJ1ozN2krdaH7bNKkTF"; Conf.UP_HOST = "http://up-z2.qiniu.com"//设置公钥 密钥 和你服务器所在的HOST 这里可以通过服务器获取 ... //上传方法 upload = () => { //上传参数 let params = { uri: this.state.imageUrl,//图片路径 可以通过第三方工具 如:ImageCropPicker等获取本地图片路径 key: "tesst",//要上传的key _aa: "aa", //自定义参数, _bb: "bb", } //构建上传策略 let policy = { scope: "niangao-sos:tesst",//记得这里如果格式为<bucket>:<key>形式的话,key要与params里的key保持一致,详见七牛上传策略 returnBody://returnBody 详见上传策略 { name: "$(fname)",//获取文件名 size: "$(fsize)",//获取文件大小 w: "$(imageInfo.width)",//... h: "$(imageInfo.height)",//... hash: "$(etag)",//... _bb: "$(x:bb)"//获取自定义参数 }, } //进行文件上传 Rpc.uploadFile(params, policy).then((data) => { console.log(data);//打印上传成功后参数 /* 格式如下 { "name": "IMG_20171124_193927_HDR-compressed.jpg", "size": 29941, "w": 260, "h": 195, "hash": "FndeZ_b_ZvlsE-3aS5U6yTTR6BZn", "_bb": "bb" } */ }).catch((err) => { console.log(err) /* 格式如下 { "readyState": 4, "data": "{\"error\":\"key doesn't match with scope\"}", "textData": "{\"error\":\"key doesn't match with scope\"}", "status": 403 } */ }); }
相关文章推荐
- ASP.NET实现上传文件并修改其文件名
- struts2实现文件上传源码
- Struts实现单文件上传、修改、删除(以图片为例)
- 再次奉献源码,webservice实现的多线程断点文件上传下载
- Struts实现单文件上传、修改、删除(以图片为例)
- PHP实现文件上传的例子(附详细源码)
- PHP实现文件上传的程序源码
- Android+struts2实现文件图片上传,附源码(侧重服务端开发)
- 【Flume】flume ng中HDFS sink设置按天滚动,0点滚动文件,修改源码实现
- FileUpload实现文件上传下载3-修改文件名显示包含中文的文件
- 利用commons-fileupload实现文件的上传(源码)
- java实现文件上传,文件下载功能 源码
- 一次提交实现注册或修改信息并上传图片文件
- struts2+ckeditor+ckfinder实现文件的上传、从数据库获取数据、修改并提交到数据库中保存
- Struts实现单文件上传、修改、删除(以图片为例)
- 利用commons-fileupload实现文件的上传(源码)
- 项目开发技巧(四):使用JspSmartupload实现文件上传下载(一):JspSmart之upload组件源码及使用
- struts2+ckeditor+ckfinder实现文件的上传、从数据库获取数据、修改并提交到数据库中保存
- 使用struts2实现多文件上传源码
- PHP实现文件上传的例子(附详细源码)