From 08f243e8a3ffea088baff3f55b46cc6e61fcec35 Mon Sep 17 00:00:00 2001 From: blak-kong <546598185@qq.com> Date: Thu, 11 Jan 2024 11:13:48 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=96=B0=E5=AF=BC=E5=85=A5=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=EF=BC=8C=E5=B9=B6=E5=88=A0=E9=99=A4=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=A4=B9=E4=B8=AD=E9=9A=90=E8=97=8F=E7=9A=84.git=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E5=A4=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/wxFormdata/README.md | 64 ++++++ src/utils/wxFormdata/formData.js | 146 ++++++++++++++ src/utils/wxFormdata/mimeMap.js | 324 ++++++++++++++++++++++++++++++ src/utils/wxFormdata/package.json | 22 ++ 4 files changed, 556 insertions(+) create mode 100644 src/utils/wxFormdata/README.md create mode 100644 src/utils/wxFormdata/formData.js create mode 100644 src/utils/wxFormdata/mimeMap.js create mode 100644 src/utils/wxFormdata/package.json diff --git a/src/utils/wxFormdata/README.md b/src/utils/wxFormdata/README.md new file mode 100644 index 0000000..5d6900f --- /dev/null +++ b/src/utils/wxFormdata/README.md @@ -0,0 +1,64 @@ +# wx-formdata +在小程序中使用formdata上传数据,可实现多文件上传 + +# 用法 +跟浏览器中的FormData对象类似 +引入js文件 +```js +const FormData = require('./formData.js') +``` +new一个FormData对象 +```js +let formData = new FormData(); +``` +调用它的[append()](#formdataappend)方法来添加字段或者调用[appendFile()](#formdataappendfile)方法添加文件 +```js +formData.append("name", "value"); +formData.appendFile("file", filepath, "文件名"); +``` +添加完成后调用它的[getData()](#formdatagetdata)生成上传数据,之后调用小程序的wx.request提交请求 +```js +let data = formData.getData(); +wx.request({ + url: 'https://接口地址', + header: { + 'content-type': data.contentType + }, + data: data.buffer, +}); +``` + +# 成员函数 +### FormData.append() +#### 语法 +```js +formData.append(name, value); +``` +#### 参数 +| 参数名 | 描述 | +| :---------- | :-----------| +| name | value中包含的数据对应的表单名称 | +| value | 表单的值 | + +### FormData.appendFile() +#### 语法 +```js +formData.appendFile(name, filepath, fileName); +``` +#### 参数 +| 参数名 | 描述 | +| :---------- | :-----------| +| name | value中包含的数据对应的表单名称 | +| filepath | 文件路径 | +| fileName | 文件名【可选】 | + +### FormData.getData() +#### 语法 +```js +let data = formData.getData(); +``` +#### 返回值对象属性 +| 属性名 | 描述 | +| :---------- | :-----------| +| buffer | 表单数据的ArrayBuffer对象 | +| contentType | http请求Content-Type头部内容 | diff --git a/src/utils/wxFormdata/formData.js b/src/utils/wxFormdata/formData.js new file mode 100644 index 0000000..419456e --- /dev/null +++ b/src/utils/wxFormdata/formData.js @@ -0,0 +1,146 @@ +const Taro = require('@tarojs/taro'); +const mimeMap = require('./mimeMap.js'); + +function FormData() { + let fileManager = Taro.getFileSystemManager(); + let data = {}; + let files = []; + + this.append = (name, value) => { + data[name] = value; + return true; + }; + + this.appendFile = (name, path, fileName) => { + let buffer = fileManager.readFileSync(path); + if (Object.prototype.toString.call(buffer).indexOf('ArrayBuffer') < 0) { + return false; + } + + if (!fileName) { + fileName = getFileNameFromPath(path); + } + + files.push({ + name: name, + buffer: buffer, + fileName: fileName, + }); + return true; + }; + + this.getData = () => convert(data, files); +} + +function getFileNameFromPath(path) { + let idx = path.lastIndexOf('/'); + return path.substr(idx + 1); +} + +function convert(data, files) { + let boundaryKey = 'wxmpFormBoundary' + randString(); // 数据分割符,一般是随机的字符串 + let boundary = '--' + boundaryKey; + let endBoundary = boundary + '--'; + + let postArray = []; + //拼接参数 + if (data && Object.prototype.toString.call(data) == '[object Object]') { + for (let key in data) { + postArray = postArray.concat(formDataArray(boundary, key, data[key])); + } + } + //拼接文件 + if (files && Object.prototype.toString.call(files) == '[object Array]') { + for (let i in files) { + let file = files[i]; + postArray = postArray.concat(formDataArray(boundary, file.name, file.buffer, file.fileName)); + } + } + //结尾 + let endBoundaryArray = []; + endBoundaryArray.push(...endBoundary.toUtf8Bytes()); + postArray = postArray.concat(endBoundaryArray); + return { + contentType: 'multipart/form-data; boundary=' + boundaryKey, + buffer: new Uint8Array(postArray).buffer, + }; +} + +function randString() { + var result = ''; + var chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + for (var i = 17; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)]; + return result; +} + +function formDataArray(boundary, name, value, fileName) { + let dataString = ''; + let isFile = !!fileName; + + dataString += boundary + '\r\n'; + dataString += 'Content-Disposition: form-data; name="' + name + '"'; + if (isFile) { + dataString += '; filename="' + fileName + '"' + '\r\n'; + dataString += 'Content-Type: ' + getFileMime(fileName) + '\r\n\r\n'; + } else { + dataString += '\r\n\r\n'; + dataString += value; + } + + var dataArray = []; + dataArray.push(...dataString.toUtf8Bytes()); + + if (isFile) { + let fileArray = new Uint8Array(value); + dataArray = dataArray.concat(Array.prototype.slice.call(fileArray)); + } + dataArray.push(...'\r'.toUtf8Bytes()); + dataArray.push(...'\n'.toUtf8Bytes()); + + return dataArray; +} + +function getFileMime(fileName) { + let idx = fileName.lastIndexOf('.'); + let mime = mimeMap[fileName.substr(idx)]; + return mime ? mime : 'application/octet-stream'; +} + +String.prototype.toUtf8Bytes = function () { + var str = this; + var bytes = []; + for (var i = 0; i < str.length; i++) { + bytes.push(...str.utf8CodeAt(i)); + if (str.codePointAt(i) > 0xffff) { + i++; + } + } + return bytes; +}; + +String.prototype.utf8CodeAt = function (i) { + var str = this; + var out = [], + p = 0; + var c = str.charCodeAt(i); + if (c < 128) { + out[p++] = c; + } else if (c < 2048) { + out[p++] = (c >> 6) | 192; + out[p++] = (c & 63) | 128; + } else if ((c & 0xfc00) == 0xd800 && i + 1 < str.length && (str.charCodeAt(i + 1) & 0xfc00) == 0xdc00) { + // Surrogate Pair + c = 0x10000 + ((c & 0x03ff) << 10) + (str.charCodeAt(++i) & 0x03ff); + out[p++] = (c >> 18) | 240; + out[p++] = ((c >> 12) & 63) | 128; + out[p++] = ((c >> 6) & 63) | 128; + out[p++] = (c & 63) | 128; + } else { + out[p++] = (c >> 12) | 224; + out[p++] = ((c >> 6) & 63) | 128; + out[p++] = (c & 63) | 128; + } + return out; +}; + +module.exports = FormData; diff --git a/src/utils/wxFormdata/mimeMap.js b/src/utils/wxFormdata/mimeMap.js new file mode 100644 index 0000000..51018f4 --- /dev/null +++ b/src/utils/wxFormdata/mimeMap.js @@ -0,0 +1,324 @@ +module.exports = { + 0.001: 'application/x-001', + 0.323: 'text/h323', + 0.907: 'drawing/907', + '.acp': 'audio/x-mei-aac', + '.aif': 'audio/aiff', + '.aiff': 'audio/aiff', + '.asa': 'text/asa', + '.asp': 'text/asp', + '.au': 'audio/basic', + '.awf': 'application/vnd.adobe.workflow', + '.bmp': 'application/x-bmp', + '.c4t': 'application/x-c4t', + '.cal': 'application/x-cals', + '.cdf': 'application/x-netcdf', + '.cel': 'application/x-cel', + '.cg4': 'application/x-g4', + '.cit': 'application/x-cit', + '.cml': 'text/xml', + '.cmx': 'application/x-cmx', + '.crl': 'application/pkix-crl', + '.csi': 'application/x-csi', + '.cut': 'application/x-cut', + '.dbm': 'application/x-dbm', + '.dcd': 'text/xml', + '.der': 'application/x-x509-ca-cert', + '.dib': 'application/x-dib', + '.doc': 'application/msword', + '.drw': 'application/x-drw', + '.dwg': 'application/x-dwg', + '.dxf': 'application/x-dxf', + '.emf': 'application/x-emf', + '.ent': 'text/xml', + '.etd': 'application/x-ebx', + '.fax': 'image/fax', + '.fif': 'application/fractals', + '.frm': 'application/x-frm', + '.gbr': 'application/x-gbr', + '.gif': 'image/gif', + '.gp4': 'application/x-gp4', + '.hmr': 'application/x-hmr', + '.hpl': 'application/x-hpl', + '.hrf': 'application/x-hrf', + '.htc': 'text/x-component', + '.html': 'text/html', + '.htx': 'text/html', + '.ico': 'image/x-icon', + '.iff': 'application/x-iff', + '.igs': 'application/x-igs', + '.img': 'application/x-img', + '.isp': 'application/x-internet-signup', + '.java': 'java/*', + '.jpe': 'image/jpeg', + '.jpeg': 'image/jpeg', + '.jpg': 'application/x-jpg', + '.jsp': 'text/html', + '.lar': 'application/x-laplayer-reg', + '.lavs': 'audio/x-liquid-secure', + '.lmsff': 'audio/x-la-lms', + '.ltr': 'application/x-ltr', + '.m2v': 'video/x-mpeg', + '.m4e': 'video/mpeg4', + '.man': 'application/x-troff-man', + '.mdb': 'application/msaccess', + '.mfp': 'application/x-shockwave-flash', + '.mhtml': 'message/rfc822', + '.mid': 'audio/mid', + '.mil': 'application/x-mil', + '.mnd': 'audio/x-musicnet-download', + '.mocha': 'application/x-javascript', + '.mp1': 'audio/mp1', + '.mp2v': 'video/mpeg', + '.mp4': 'video/mpeg4', + '.mpd': 'application/vnd.ms-project', + '.mpeg': 'video/mpg', + '.mpga': 'audio/rn-mpeg', + '.mps': 'video/x-mpeg', + '.mpv': 'video/mpg', + '.mpw': 'application/vnd.ms-project', + '.mtx': 'text/xml', + '.net': 'image/pnetvue', + '.nws': 'message/rfc822', + '.out': 'application/x-out', + '.p12': 'application/x-pkcs12', + '.p7c': 'application/pkcs7-mime', + '.p7r': 'application/x-pkcs7-certreqresp', + '.pc5': 'application/x-pc5', + '.pcl': 'application/x-pcl', + '.pdf': 'application/pdf', + '.pdx': 'application/vnd.adobe.pdx', + '.pgl': 'application/x-pgl', + '.pko': 'application/vnd.ms-pki.pko', + '.plg': 'text/html', + '.plt': 'application/x-plt', + '.ppa': 'application/vnd.ms-powerpoint', + '.pps': 'application/vnd.ms-powerpoint', + '.ppt': 'application/x-ppt', + '.prf': 'application/pics-rules', + '.prt': 'application/x-prt', + '.ps': 'application/postscript', + '.pwz': 'application/vnd.ms-powerpoint', + '.ra': 'audio/vnd.rn-realaudio', + '.ras': 'application/x-ras', + '.rdf': 'text/xml', + '.red': 'application/x-red', + '.rjs': 'application/vnd.rn-realsystem-rjs', + '.rlc': 'application/x-rlc', + '.rm': 'application/vnd.rn-realmedia', + '.rmi': 'audio/mid', + '.rmm': 'audio/x-pn-realaudio', + '.rms': 'application/vnd.rn-realmedia-secure', + '.rmx': 'application/vnd.rn-realsystem-rmx', + '.rp': 'image/vnd.rn-realpix', + '.rsml': 'application/vnd.rn-rsml', + '.rtf': 'application/msword', + '.rv': 'video/vnd.rn-realvideo', + '.sat': 'application/x-sat', + '.sdw': 'application/x-sdw', + '.slb': 'application/x-slb', + '.slk': 'drawing/x-slk', + '.smil': 'application/smil', + '.snd': 'audio/basic', + '.sor': 'text/plain', + '.spl': 'application/futuresplash', + '.ssm': 'application/streamingmedia', + '.stl': 'application/vnd.ms-pki.stl', + '.sty': 'application/x-sty', + '.swf': 'application/x-shockwave-flash', + '.tg4': 'application/x-tg4', + '.tif': 'image/tiff', + '.tiff': 'image/tiff', + '.top': 'drawing/x-top', + '.tsd': 'text/xml', + '.uin': 'application/x-icq', + '.vcf': 'text/x-vcard', + '.vdx': 'application/vnd.visio', + '.vpg': 'application/x-vpeg005', + '.vsw': 'application/vnd.visio', + '.vtx': 'application/vnd.visio', + '.wav': 'audio/wav', + '.wb1': 'application/x-wb1', + '.wb3': 'application/x-wb3', + '.wiz': 'application/msword', + '.wk4': 'application/x-wk4', + '.wks': 'application/x-wks', + '.wma': 'audio/x-ms-wma', + '.wmf': 'application/x-wmf', + '.wmv': 'video/x-ms-wmv', + '.wmz': 'application/x-ms-wmz', + '.wpd': 'application/x-wpd', + '.wpl': 'application/vnd.ms-wpl', + '.wr1': 'application/x-wr1', + '.wrk': 'application/x-wrk', + '.ws2': 'application/x-ws', + '.wsdl': 'text/xml', + '.xdp': 'application/vnd.adobe.xdp', + '.xfd': 'application/vnd.adobe.xfd', + '.xhtml': 'text/html', + '.xml': 'text/xml', + '.xq': 'text/xml', + '.xquery': 'text/xml', + '.xsl': 'text/xml', + '.xwd': 'application/x-xwd', + '.sis': 'application/vnd.symbian.install', + '.x_t': 'application/x-x_t', + '.apk': 'application/vnd.android.package-archive', + 0.301: 'application/x-301', + 0.906: 'application/x-906', + '.a11': 'application/x-a11', + '.ai': 'application/postscript', + '.aifc': 'audio/aiff', + '.anv': 'application/x-anv', + '.asf': 'video/x-ms-asf', + '.asx': 'video/x-ms-asf', + '.avi': 'video/avi', + '.biz': 'text/xml', + '.bot': 'application/x-bot', + '.c90': 'application/x-c90', + '.cat': 'application/vnd.ms-pki.seccat', + '.cdr': 'application/x-cdr', + '.cer': 'application/x-x509-ca-cert', + '.cgm': 'application/x-cgm', + '.class': 'java/*', + '.cmp': 'application/x-cmp', + '.cot': 'application/x-cot', + '.crt': 'application/x-x509-ca-cert', + '.css': 'text/css', + '.dbf': 'application/x-dbf', + '.dbx': 'application/x-dbx', + '.dcx': 'application/x-dcx', + '.dgn': 'application/x-dgn', + '.dll': 'application/x-msdownload', + '.dot': 'application/msword', + '.dtd': 'text/xml', + '.dwf': 'application/x-dwf', + '.dxb': 'application/x-dxb', + '.edn': 'application/vnd.adobe.edn', + '.eml': 'message/rfc822', + '.epi': 'application/x-epi', + '.exe': 'application/x-msdownload', + '.fdf': 'application/vnd.fdf', + '.fo': 'text/xml', + '.g4': 'application/x-g4', + '.gl2': 'application/x-gl2', + '.hgl': 'application/x-hgl', + '.hpg': 'application/x-hpgl', + '.hqx': 'application/mac-binhex40', + '.hta': 'application/hta', + '.htm': 'text/html', + '.htt': 'text/webviewhtml', + '.icb': 'application/x-icb', + '.ig4': 'application/x-g4', + '.iii': 'application/x-iphone', + '.ins': 'application/x-internet-signup', + '.IVF': 'video/x-ivf', + '.jfif': 'image/jpeg', + '.js': 'application/x-javascript', + '.la1': 'audio/x-liquid-file', + '.latex': 'application/x-latex', + '.lbm': 'application/x-lbm', + '.ls': 'application/x-javascript', + '.m1v': 'video/x-mpeg', + '.m3u': 'audio/mpegurl', + '.mac': 'application/x-mac', + '.math': 'text/xml', + '.mht': 'message/rfc822', + '.mi': 'application/x-mi', + '.midi': 'audio/mid', + '.mml': 'text/xml', + '.mns': 'audio/x-musicnet-stream', + '.movie': 'video/x-sgi-movie', + '.mp2': 'audio/mp2', + '.mp3': 'audio/mp3', + '.mpa': 'video/x-mpg', + '.mpe': 'video/x-mpeg', + '.mpg': 'video/mpg', + '.mpp': 'application/vnd.ms-project', + '.mpt': 'application/vnd.ms-project', + '.mpv2': 'video/mpeg', + '.mpx': 'application/vnd.ms-project', + '.mxp': 'application/x-mmxp', + '.nrf': 'application/x-nrf', + '.odc': 'text/x-ms-odc', + '.p10': 'application/pkcs10', + '.p7b': 'application/x-pkcs7-certificates', + '.p7m': 'application/pkcs7-mime', + '.p7s': 'application/pkcs7-signature', + '.pci': 'application/x-pci', + '.pcx': 'application/x-pcx', + '.pfx': 'application/x-pkcs12', + '.pic': 'application/x-pic', + '.pl': 'application/x-perl', + '.pls': 'audio/scpls', + '.png': 'image/png', + '.pot': 'application/vnd.ms-powerpoint', + '.ppm': 'application/x-ppm', + '.pr': 'application/x-pr', + '.prn': 'application/x-prn', + '.ptn': 'application/x-ptn', + '.r3t': 'text/vnd.rn-realtext3d', + '.ram': 'audio/x-pn-realaudio', + '.rat': 'application/rat-file', + '.rec': 'application/vnd.rn-recording', + '.rgb': 'application/x-rgb', + '.rjt': 'application/vnd.rn-realsystem-rjt', + '.rle': 'application/x-rle', + '.rmf': 'application/vnd.adobe.rmf', + '.rmj': 'application/vnd.rn-realsystem-rmj', + '.rmp': 'application/vnd.rn-rn_music_package', + '.rmvb': 'application/vnd.rn-realmedia-vbr', + '.rnx': 'application/vnd.rn-realplayer', + '.rpm': 'audio/x-pn-realaudio-plugin', + '.rt': 'text/vnd.rn-realtext', + '.sam': 'application/x-sam', + '.sdp': 'application/sdp', + '.sit': 'application/x-stuffit', + '.sld': 'application/x-sld', + '.smi': 'application/smil', + '.smk': 'application/x-smk', + '.sol': 'text/plain', + '.spc': 'application/x-pkcs7-certificates', + '.spp': 'text/xml', + '.sst': 'application/vnd.ms-pki.certstore', + '.stm': 'text/html', + '.svg': 'text/xml', + '.tdf': 'application/x-tdf', + '.tga': 'application/x-tga', + '.torrent': 'application/x-bittorrent', + '.txt': 'text/plain', + '.uls': 'text/iuls', + '.vda': 'application/x-vda', + '.vml': 'text/xml', + '.vsd': 'application/vnd.visio', + '.vst': 'application/x-vst', + '.vxml': 'text/xml', + '.wax': 'audio/x-ms-wax', + '.wb2': 'application/x-wb2', + '.wbmp': 'image/vnd.wap.wbmp', + '.wk3': 'application/x-wk3', + '.wkq': 'application/x-wkq', + '.wm': 'video/x-ms-wm', + '.wmd': 'application/x-ms-wmd', + '.wml': 'text/vnd.wap.wml', + '.wmx': 'video/x-ms-wmx', + '.wp6': 'application/x-wp6', + '.wpg': 'application/x-wpg', + '.wq1': 'application/x-wq1', + '.wri': 'application/x-wri', + '.ws': 'application/x-ws', + '.wsc': 'text/scriptlet', + '.wvx': 'video/x-ms-wvx', + '.xdr': 'text/xml', + '.xfdf': 'application/vnd.adobe.xfdf', + '.xls': 'application/vnd.ms-excel', + '.xpl': 'audio/scpls', + '.xql': 'text/xml', + '.xsd': 'text/xml', + '.xslt': 'text/xml', + '.x_b': 'application/x-x_b', + '.sisx': 'application/vnd.symbian.install', + '.ipa': 'application/vnd.iphone', + '.xap': 'application/x-silverlight-app', + '.zip': 'application/x-zip-compressed', +}; diff --git a/src/utils/wxFormdata/package.json b/src/utils/wxFormdata/package.json new file mode 100644 index 0000000..97dbe17 --- /dev/null +++ b/src/utils/wxFormdata/package.json @@ -0,0 +1,22 @@ +{ + "name": "@zlyboy/wx-formdata", + "version": "1.0.2", + "description": "在微信小程序中使用formdata上传数据,可实现多文件上传", + "main": "formData.js", + "author": "zlyboy", + "bugs": { + "url": "https://github.com/zlyboy/wx-formdata/issues" + }, + "homepage": "https://github.com/zlyboy/wx-formdata#readme", + "keywords": [ + "小程序" + ], + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/zlyboy/wx-formdata.git" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + } +}