koa踩坑路之–传输blob或ArrayBuffer,koa-body意想不到的坑~~~~~
提示:本来打算尝试一下直接把input上传的blob二进制对象或者fileReader.readAsArrayBuffer得到的二进制缓冲区ArrayBuffer直接传给后台,但是后台接收到的并非blob和ArrayBuffer,而是一个稀奇古怪的对象(为什么说稀奇古怪呢,自己打印一下就知道了);
文章目录
- 前言
- 一、Blob或ArrayBuffer直接传输
- 二、使用步骤
- 1.vue中HelloWorld.vue
- 2.vue中axios.js
- 3.koa中routes.js
- 4.koa中app.js
- 总结
前言
学习多种方式上传图片—学习文档,大神绕行
一、Blob或ArrayBuffer直接传输
示例:koa-body配置的时候,multipart为true,是为了接收formData数据并解析,问题就出在了这里,formData是可以解析了,
blob和arrayBuffer无法直接接收解析了
//如果想直接传输blob和arrayBuffer,去koa的app.js//注释掉koa-body,//注释掉koa-body,//注释掉koa-body,//重要的事情说3遍
app.use(koaBody({ multipart: true,formidable: {//上传文件存储目录uploadDir: path.join(__dirname, `/public/uploads/`),//允许保留后缀名keepExtensions: true,multipart: true,},jsonLimit:'10mb',formLimit:'10mb',textLimit:'10mb'
}));
koa-body源码中对接收到的数据进行了处理,所以配置过koa-body的项目,接收到的数据都会处理成一个新的对象。
下面附上koa-body源码
通过//--------xxxxxx---------标注问题冲突的点
/*** koa-body - index.js* Copyright(c) 2014* MIT Licensed** @author Daryl Lau (@dlau)* @author Charlike Mike Reagent (@tunnckoCore)* @api private*/'use strict';/*** Module dependencies.*/const buddy = require('co-body');
const forms = require('formidable');
const symbolUnparsed = require('./unparsed.js');/*** Expose `requestbody()`.*/module.exports = requestbody;const jsonTypes = ['application/json','application/json-patch+json','application/vnd.api+json','application/csp-report'
];/**** @param {Object} options* @see https://github.com/dlau/koa-body* @api public*/
function requestbody(opts) {opts = opts || {};opts.onError = 'onError' in opts ? opts.onError : false;opts.patchNode = 'patchNode' in opts ? opts.patchNode : false;opts.patchKoa = 'patchKoa' in opts ? opts.patchKoa : true;opts.multipart = 'multipart' in opts ? opts.multipart : false;opts.urlencoded = 'urlencoded' in opts ? opts.urlencoded : true;opts.json = 'json' in opts ? opts.json : true;opts.text = 'text' in opts ? opts.text : true;opts.encoding = 'encoding' in opts ? opts.encoding : 'utf-8';opts.jsonLimit = 'jsonLimit' in opts ? opts.jsonLimit : '1mb';opts.jsonStrict = 'jsonStrict' in opts ? opts.jsonStrict : true;opts.formLimit = 'formLimit' in opts ? opts.formLimit : '56kb';opts.queryString = 'queryString' in opts ? opts.queryString : null;opts.formidable = 'formidable' in opts ? opts.formidable : {};opts.includeUnparsed = 'includeUnparsed' in opts ? opts.includeUnparsed : falseopts.textLimit = 'textLimit' in opts ? opts.textLimit : '56kb';// @todo: next major version, opts.strict support should be removedif (opts.strict && opts.parsedMethods) {throw new Error('Cannot use strict and parsedMethods options at the same time.')}if ('strict' in opts) {console.warn('DEPRECATED: opts.strict has been deprecated in favor of opts.parsedMethods.')if (opts.strict) {opts.parsedMethods = ['POST', 'PUT', 'PATCH']} else {opts.parsedMethods = ['POST', 'PUT', 'PATCH', 'GET', 'HEAD', 'DELETE']}}opts.parsedMethods = 'parsedMethods' in opts ? opts.parsedMethods : ['POST', 'PUT', 'PATCH']opts.parsedMethods = opts.parsedMethods.map(function (method) { return method.toUpperCase() })return function (ctx, next) {var bodyPromise;// only parse the body on specifically chosen methodsif (opts.parsedMethods.includes(ctx.method.toUpperCase())) {try {if (opts.json && ctx.is(jsonTypes)) { //--------xxxxxx---------对类型判断,分别进行不同处理bodyPromise = buddy.json(ctx, {encoding: opts.encoding,limit: opts.jsonLimit,strict: opts.jsonStrict,returnRawBody: opts.includeUnparsed});} else if (opts.urlencoded && ctx.is('urlencoded')) {bodyPromise = buddy.form(ctx, {encoding: opts.encoding,limit: opts.formLimit,queryString: opts.queryString,returnRawBody: opts.includeUnparsed});} else if (opts.text && ctx.is('text/*')) {bodyPromise = buddy.text(ctx, {encoding: opts.encoding,limit: opts.textLimit,returnRawBody: opts.includeUnparsed});} else if (opts.multipart && ctx.is('multipart')) { //--------xxxxxx---------当设置multipart后,执行了formybodyPromise = formy(ctx, opts.formidable);}} catch (parsingError) {if (typeof opts.onError === 'function') {opts.onError(parsingError, ctx);} else {throw parsingError;}}}bodyPromise = bodyPromise || Promise.resolve({});return bodyPromise.catch(function(parsingError) {if (typeof opts.onError === 'function') {opts.onError(parsingError, ctx);} else {throw parsingError;}return next();}).then(function(body) {if (opts.patchNode) {if (isMultiPart(ctx, opts)) {ctx.req.body = body.fields;ctx.req.files = body.files;} else if (opts.includeUnparsed) {ctx.req.body = body.parsed || {};if (! ctx.is('text/*')) {ctx.req.body[symbolUnparsed] = body.raw;}} else {ctx.req.body = body;}}if (opts.patchKoa) {if (isMultiPart(ctx, opts)) {ctx.request.body = body.fields;ctx.request.files = body.files;} else if (opts.includeUnparsed) {ctx.request.body = body.parsed || {};if (! ctx.is('text/*')) {ctx.request.body[symbolUnparsed] = body.raw;}} else {ctx.request.body = body;}}return next();})};
}/*** Check if multipart handling is enabled and that this is a multipart request** @param {Object} ctx* @param {Object} opts* @return {Boolean} true if request is multipart and being treated as so* @api private*/
function isMultiPart(ctx, opts) {return opts.multipart && ctx.is('multipart');
}/*** Donable formidable** @param {Stream} ctx* @param {Object} opts* @return {Promise}* @api private*/
function formy(ctx, opts) { //--------xxxxxx---------这里就是formy了return new Promise(function (resolve, reject) {var fields = {};var files = {};var form = new forms.IncomingForm(opts);form.on('end', function () {return resolve({fields: fields,files: files});}).on('error', function (err) {return reject(err);}).on('field', function (field, value) {if (fields[field]) { //--------xxxxxx---------对field进行了处理if (Array.isArray(fields[field])) {fields[field].push(value);} else {fields[field] = [fields[field], value];}} else {fields[field] = value;}}).on('file', function (field, file) { //--------xxxxxx---------对file进行了处理if (files[field]) {if (Array.isArray(files[field])) {files[field].push(file);} else {files[field] = [files[field], file];}} else {files[field] = file;}});if (opts.onFileBegin) {form.on('fileBegin', opts.onFileBegin);}form.parse(ctx.req);});
}
当我们直接传blob或者arrayBuffer时,会被重新生成一个对象返给ctx.request.body,然后这个对象经过不懈的努力,解出来的字符串或buffer都和原始数据有冲突(有能力的小伙伴可以自行试一下),于是有了下面的解决方法,仅限测试踩坑,实际应用中用处不大
二、使用步骤
1.vue中HelloWorld.vue
代码如下(示例):
<template><div class="hello"><h1>{{msg}}</h1><el-upload class="avatar-uploader" action="''" :http-request="uploadBuffer" :show-file-list="false" :before-upload="beforeAvatarUpload"><img v-if="imgUrl" :src="imgUrl" class="avatar"><i v-else class="el-icon-plus avatar-uploader-icon"></i></el-upload></div>
</template>
import { uploadImg } from "@/axios/index";
export default {name: "HelloWorld",data() {return {imgUrl: null,msg: "", //"活在当下!",};},methods: {beforeAvatarUpload(file) {const isImage = file.type === "image/jpeg" || "image/png";const limitSize = file.size / 1024 / 1024 < 2;if (!isImage) {this.$message.error("上传头像图片只能是 JPG或png 格式!");}if (!limitSize) {this.$message.error("上传头像图片大小不能超过 2MB!");}return isImage && limitSize;},async uploadBuffer(item) {//传blobuploadBuffer(item.file);//传arrayBuffer// const fileReader = new FileReader();// let sourceId = new Date().getTime() + item.file.name.split(".")[0];// fileReader.onload = (e) => {// let content = e.target.result;// uploadBuffer(content);// };// await fileReader.readAsArrayBuffer(item.file);// await fileReader.readAsText(item.file, "utf8");},},
};
</script>
2.vue中axios.js
代码如下(示例):
import axios from 'axios';
import { Loading, Message } from 'element-ui';let urlData = { basicUrl: "http://127.0.0.1:3002" }let loading;const instance = axios.create({baseURL: urlData.basicUrl,timeout: 1000,headers: { "X-Requested-With": "XMLHttpRequest" },withCredentials: false,
});// 添加请求拦截器
instance.interceptors.request.use(function (config) {// 在发送请求之前做些什么loading = Loading.service({lock: true, // 是否锁屏text: '正在加载...', // 加载动画的文字spinner: 'el-icon-loading', // 引入的loading图标background: 'rgba(0, 0, 0, 0.3)', // 背景颜色})return config;
}, function (error) {// 对请求错误做些什么return Promise.reject(error);
});// 添加响应拦截器
instance.interceptors.response.use(function (response) {loading.close();// 对响应数据做点什么return response.data;
}, function (error) {// 对响应错误做点什么return Promise.reject(error);
});//GET
export function getUserInfoById(id) {let params={ id }return instance.get('/getUserInfo', { params });
}//POST
export async function uploadBuffer(data) {return instance.post('/uploadBuffer', data);
}export default instance;
3.koa中routes.js
代码如下(示例):
import Router from 'koa-router';
import fs, { readFileSync } from 'fs';const router = new Router();export const uploadBuffer = async ctx=>{let params = [];ctx.req.on('data', (chunk) => {params.push(chunk);})ctx.req.on('end', (chunk) => {let buffer = Buffer.concat(params);fs.writeFileSync(`./public/uploads/111.png`,buffer);})ctx.body = {code: 200,data: {},msg: "",}
}
router.post('/uploadBuffer',uploadBuffer);export default router;
4.koa中app.js
代码如下(示例):
注释掉koaBody的引用
import koa from 'koa';
import cors from 'koa-cors';
import router from './routes/routes.js';
import staticFiles from 'koa-static';
import koaBody from 'koa-body';import path from 'path';const __dirname = path.resolve();
const app = new koa();app.use(cors({ // 指定一个或多个可以跨域的域名origin: function (ctx) { // 设置允许来自指定域名请求if (ctx.url === '/') {return "*"; // 允许来自所有域名请求, 这个不管用}// return 'http://localhost:8000'; // 这样就能只允许 http://localhost:8000 这个域名的请求了return '*'; // 这样就能只允许 http://localhost:8000 这个域名的请求了},maxAge: 5, // 指定本次预检请求的有效期,单位为秒。credentials: true, // 是否允许发送CookieallowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], // 设置所允许的HTTP请求方法allowHeaders: ['Content-Type', 'Authorization', 'Accept'], // 设置服务器支持的所有头信息字段exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'] // 设置获取其他自定义字段
}))// app.use(koaBody({
// multipart: false,
// formidable: {
// //上传文件存储目录
// uploadDir: path.join(__dirname, `/public/uploads/`),
// //允许保留后缀名
// keepExtensions: true,
// multipart: true,
// },
// jsonLimit:'10mb',
// formLimit:'10mb',
// textLimit:'10mb'
// }));
//解析formdata过来的数据
app.use(router.routes());
app.use(router.allowedMethods());
app.use(staticFiles(__dirname + '/public'));app.listen('3002');
console.log("项目启动,访问:","localhost:3002");
总结
踩坑路漫漫长@~@
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
