用 wails 包装web 文件上传的问题
问题发现
wails 包装了现有的web 项目,在测验的时分发现,文件上传的时分,上传失利。看了下恳求,文件传了,没问题。
难道是有鬼了!!!
发动后台,打断点持续找问题,发现后端底子没收到文件,凭空消失了吗?
寻觅问题
百度感觉是处理不了啥问题,然后就在github 上找到wails ,依据问题的表现,用Ai 翻译了下,提了个issues
Description
I used the AccessServer's handler to receive requests from the frontend, but I found that the ContentLength of the received POST request is always 0, and there is no data in the body either.
前端经过 表单上传了一个文件,可是后台无法承受文件
To Reproduce
I created a form in the frontend to upload files, but the backend is not receiving the files.
前端经过 表单上传了一个文件,可是后台无法承受文件
Expected behaviour
can upload file
能上传文件
Screenshots
问题是下午5点钟提上去的,结果 5点26的时分就得到回复,这个反馈速度还是很快的。答复的大致意思就是,这个是webview2 的一个bug ,然后给了个链接,曩昔看了下,的确如此
MicrosoftEdge/WebView2Feedback#2162
这个bug 已经有很久了 commented on Feb 11, 2022 ,到现在依旧没处理,有爱好的可以点进去看下。
wails 那边回复,换种思路,用go的办法处理。
处理问题
用go 的办法处理,因为项目是最先开发的web 段,用的elementui ,上传组件是封装好的。处理方案要求要改动最小,然后就自己写了一个同名的上传组件,兼容elementui 的上传组件,在包装的这边,替换上就行了,说干就干。
go的上传逻辑如下 ,首要就是把 upload 组件的 挑选文件,和上传文件的两个过程,用go来实现,其他的坚持不变
代码实现
1,先做下go翻开文件挑选框,和上传文件的逻辑
// 翻开挑选文件对话框
func (a *App) OpenDialog() string {
// 回来挑选的文件
options := runtime.OpenDialogOptions{
// Filters: ,
}
filepath, err := runtime.OpenFileDialog(a.ctx, options)
if err != nil {
return "挑选文件失利"
}
return filepath
}
// 上传文件的办法,传入文件路径
func (a *App) UploadFile(upInfo UpdateInfo) UpdateResp {
// fmt.Println("upinfo", upInfo)
file, err := os.OpenFile(upInfo.Filename, os.O_RDONLY, 0)
if err != nil {
fmt.Println(err.Error() + upInfo.Filename)
return UpdateResp{400, err.Error()}
}
body := new(bytes.Buffer)
// 创立一个 `Writer` 目标,并将其写入到 `w` 中。
w := multipart.NewWriter(body)
// 将 `file` 目标写入到 `Writer` 中。
// 注意,这里的 `file` 目标必须实现 `io.Reader` 接口。
fileForm, err := w.CreateFormFile("file", upInfo.Filename)
if err != nil {
return UpdateResp{400, err.Error()}
}
_, err = io.Copy(fileForm, file)
if err != nil {
return UpdateResp{400, err.Error()}
}
// 封闭 `Writer` 目标。
err = w.Close()
if err != nil {
return UpdateResp{400, err.Error()}
}
// 发送 `POST` 恳求。
req, err := http.NewRequest("POST", BaseUrl+upInfo.Action, body)
if err != nil {
return UpdateResp{400, err.Error()}
}
// 设置恳求头。
req.Header.Set("Content-Type", w.FormDataContentType())
req.Header.Set("Authorization", upInfo.Header["Authorization"])
// 发送恳求。
resp, err := http.DefaultClient.Do(req)
if err != nil {
return UpdateResp{400, err.Error()}
}
// 封闭呼应。
defer resp.Body.Close()
// 检查呼应状态码。
if resp.StatusCode != http.StatusOK {
return UpdateResp{400, "上传文件失利"}
}
respBy, _ := io.ReadAll(resp.Body)
// 回来 nil。
return UpdateResp{200, string(respBy)}
}
2,写一个自定义的upload 组件,把UploadFile , OpenDialog 引进来,点击上传组件的时分,调用OpenDialog
<template>
<div @click="openChoseFileDlg">
<slot></slot>
</div>
</template>
<script>
import { getToken } from "@/utils/auth";
import { UploadFile,OpenDialog} from "@w/go/api/App";
export default {
name:"ElUploadCs",
props: {
action: {
type: String,
},
accept: {
type: String,
},
beforeUpload:{
type:Function,
default:()=>{
}
},
onSuccess:{
type:Function,
default:()=>{
}
},
onError:{
type:Function,
default:()=>{
}
},
onProgress:{
type:Function,
default:()=>{
}
},
},
data() {
return {
headerMsg: { Authorization: getToken() },
filename:"",
};
},
methods: {
openChoseFileDlg(){
OpenDialog().then(res=>{
console.log("chose file :",res)
if (res!=""){
this.filename = res
this.doUploadFile()
}
})
},
doUploadFile(){
let params = {
"action":this.action,
"filename":this.filename,
"header":this.headerMsg
}
console.log(params)
this.beforeUpload()
this.handleProgress()
UploadFile(params).then(res=>{
console.log(res)
if (res.code== 200) {
let resData = JSON.parse(res.data)
console.log(resData)
this.onSuccess(resData)
}else{
this.onError()
}
// this.$emit("onSuccess",resData)
})
},
handleProgress() {
if (this.utips) {
this.dialogViable = false;
this.fileUploadVisible = true;
}
},
handleError() {
if (this.utips) {
this.fileUploadVisible = false;
this.vMsg = "文件导入失利!";
this.fileSuccessVisible = true;
}
},
},
};
</script>
3,调用,引进自定义组件 ,命名为 ElUplaod,跟element-ui 里边的组件名字相同,然后在 components 中引进就可以了
import ElUpload from "@/components/upload-cs"
components: {ElUpload },