赞
踩
node.js后端服务器配置了koa-session和koa-jwt双重认证,而前端el-upload中的action只是个url,如果没有配置header会导致上传文件失败,诸如“The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'.”错误
注:使用el-upload时,node.js后端需用使用koa-body,不要和koa-bodyparser同时使用。
以下是项目中一个关于上传PDF使用el-upload的例子,仅实现了通过koa-jwt认证,但未通过koa-session认证。(koa-session解决办法:后端服务器针对上传文件的api进行白名单放行)
drag:可拖放上传文件
multiple:允许上传多个文件
method:上传方式,默认的是post,其实可以不用定义
action:后端api接口,通过这种方式来访问api容易是容易,但没考虑到后端服务器认证的问题,可以设置with-credentials来携带cookie中的session,但这是个坑我爬了半天没爬出来……,element-plus官网还介绍了http-request接口,但我觉得更坑,各种尝试都没法通过koa-session认证。
headers:设置请求头部,在这里设置Authorization可以通过koa-jwt认证,这点个赞
auto-upload:是否自动上传,默认是自动上传的,最好是改成手动
on-success:上传成功的回调函数,这是个好东西
- <template>
- <el-upload ref="uploadRef" drag multiple method="post" action="http://192.168.8.120:8802/api/mongo/upload/pdf"
- :headers="headersObj" :auto-upload="false" :on-success="uploadSuccess" :on-error="uploadError">
- <el-icon>
- <upload-filled />
- </el-icon>
- <div class="upload-text">
- 将文件拖入,<em>或者点击上传</em>
- </div>
- <template #tip>
- <div class="upload-tip">
- 一次性不要拖入太多PDF文件,仅识别PDF文件
- </div>
- <div class="pdf-parser">
- <el-button type="primary" size="small" @click="submitUpload">开始上传</el-button>
- </div>
- </template>
- </el-upload>
- </template>

注:未展示pinia pdfStore部分代码
- <script setup lang='ts'>
- import { ref } from "vue"
- import { ElMessage } from "element-plus"
- import 'element-plus/es/components/message/style/css'
- import { pdfStore } from "@/pinia/pdfStore"
-
- const usePdfStore = pdfStore()
- const uploadRef: any = ref(null)
-
- const submitUpload = async () => {
- await uploadRef.value?.submit() // 手动上传PDF文件
- usePdfStore.getRenameList() // 获取下一步的映射表
- }
-
- const uploadSuccess = () => {
- usePdfStore.isUpload = true // el-upload回调:上传成功标识为true
- ElMessage({
- message: '上传PDF文件成功!',
- type: 'success'
- })
- }
-
- const uploadError = () => {
- return ElMessage({
- message: '上传PDF文件失败!', // el-upload回调:上传失败提示错误
- type: 'error'
- })
- }
-
- const headersObj = {
- "Authorization": 'Bearer ' + localStorage.getItem('token'), // JWT认证,携带token
- }

基础使用见官网:https://www.npmjs.com/package/koa-body
-
- const fs = require('fs')
- const {koaBody} = require('koa-body') // 解析文件,对应前端的file
- const { v4:uuidv4 } = require('uuid')
-
- // 使用第三方中间件:解析挂载请求body
- // 注意:在routes之前使用
- // 注意:session和JWT通过后才会到这里
- // app.use(bodyParser({multipart:true})) // 注意要设置multipart,接收FormData()
- app.use(koaBody({
- multipart:true, // 支持文件上传
- formidable:{
- uploadDir:path.join(__dirname, './upload'), // 文件保存路径,对应file.filepath,注意要先创建对应文件夹否则不生效?
- keepExtensions:true, // 保留文件扩展名
- maxFieldsSize:50*1024*1024, // 限制50M
- multiples:true, // 允许上传多个文件
- onFileBegin:(name, file) => {
- // const subPath = uuidv4() // 生成一个随机字符串
- // fs.mkdirSync(path.join(__dirname, './upload/', `${subPath}`))
- // fs.path = path.join(__dirname, './upload/', `${subPath}`) // 定义一个
- // console.log('app.js koa-body onFileBegin subPath:', subPath)
- file.filepath = path.join(__dirname, './upload/', file.originalFilename)// 上传前的回调函数,比如重新设置路径
- // file.filepath = path.join(__dirname, './upload/', `${subPath}/`, file.originalFilename)// 上传前的回调函数,比如重新设置路径
- console.log('app.js koa-body onFileBegin file:', file)
- },
- onError: (err) => {
- appendErrorLog('app.js koa-body onError:',err) // 调用工具,将错误写入错误日志文件
- }
- },
- textLimit:'10mb',
- jsonLimit:'20mb',
- encoding:'utf-8',
- parsedMethods:['GET', 'POST', 'PUT', 'DELETE'],
- extendTypes:{
- 'text/plain':['txt'], // 括号内是文件扩展名
- 'application/pdf':['pdf']
- }
- }))

with-credential这个坑实在爬不动了,放行吧……
- // session拦截:有必要吗?
- app.use((ctx, next) => {
- // ignore login isLogin:方向
- const ignorePath = [
- '/api/login',
- '/api/isLogin',
- '/api/mongo/account/login',
- '/api/mongo/account/register',
- ]
- if (ignorePath.includes(ctx.path) || ctx.path.includes('upload')) {
- return next()
- }
- // session已登录:放行
- if (ctx.session.isLogin) {
- return next()
- }
- ctx.body = {
- status:201,
- message:'session过期,请重新登录!'
- }
- })

koa-body解析成功后,可以通过ctx.request.files来读取文件信息,注意只是信息不是内容,例如文件名、文件存放路径等信息
- router.post('/mongo/upload/pdf', async (ctx) => {
- try {
- // console.log('router mongo upload pdf files:', ctx.request.files)
- return ctx.body = {
- status: 200,
- message: '上传文件成功!'
- }
- } catch (error) {
- throw(error)
- }
- })
完结!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。