Asp.net core 2.0 +SPA檔案上傳注意事項
最近在做的一個工程,後端選用asp.net 2.0 core,前端用vue。選用core純粹是好奇,想體驗一下微軟的新技術。還有就是實在不想寫java...。技術組成如下:
- 後端:asp.net core 2.0 +JWT Auth + mongodb + RESTFul + swagger
- 前端:Vue + Vuetify
一開始一切都算順利,可是到了檔案上傳環節,遇到了一點小挫折(掩面,其實是耽誤了一天半時間),現在記錄一下:
- 前端上傳方式選擇:
首先根據微軟官網文件,asp.net core檔案上傳示例全部用的是表單+Razor的方式,後臺用IFormFile
接收。順便吐槽一下,感覺微軟總是慢半拍啊,整個core的介紹全都是MVC例子,沒有RESTFul的,資料庫全都是SQL。沒有NoSQL。
SPA檔案上傳肯定不能用表單提交,那麼可以選擇的合理方式有:
- axios
- HTML5 原生XMLHttpRequest
- jquery
- 各種封裝好的第三方庫(如
vue-upload-componen
)
以下對各種方式進行實驗:
後端--------------------------
[HttpPost("test")]
public AppResponse UploadTest(IFormFile file)
{
if (file==null)
{
return responser.ReturnError(STATUS_CODE.BAD_REQUEST, "files is empty");
}
return responser.ReturnSuccess(extraInfo: file.FileName);
}
關於檔案上傳,官方有一段文字解釋如下:
If your controller is accepting uploaded files using IFormFile but you find that the value is always null, confirm that your HTML form is specifying an enctype value of multipart/form-data. If this attribute is not set on the <form> element, the file upload will not occur and any bound IFormFile arguments will be null.
意思就是說,上傳檔案的表單必須設定enctype=multipart/form-data,否則是取不到值的。
但如果是以非表單方式上傳,前臺應該怎麼做?
前端-----------------------------
前臺搭建以下簡單頁面:
<template>
<v-card>
<h1>UPLOAD</h1>
<v-divider></v-divider>
<input type="file" ref="f" />
<v-btn @click.native="uploadOnXMLHttpRequest">使用XMLHttpRequest上傳</v-btn>
<v-btn @click.native="uploadOnAxios">使用axios上傳</v-btn>
</v-card>
</template>
- 首先說axios,經過實驗,無法上傳檔案到.net core後臺:
uploadOnAxios() {
const options = {
url: this.url,
method: 'post',
data: {
'file': this.$refs.f.files[0]
},
// headers: { 'Content-Type': undefined }//無效
// headers: { 'Content-Type': 'multipart/form-data' }//無效
}
this.$http.request(options).then(res => {
console.log(res)
})
},
上面註釋掉的兩個header,就是試圖設定enctype,其實就是表單header裡的content-type,經過測試,都沒有效果,axios始終傳送:application/json
。後臺因此拿不到值。
- HTML5 原生XMLHttpRequest
首先是關於瀏覽器支援,這個要看工程,比如我這個工程,都用到vue和vuetify了,就不考慮相容性了,放心大膽使用就行。
uploadOnXMLHttpRequest() {
const fileObj = this.$refs.f.files[0] // js 獲取檔案物件
var url = this.url // 接收上傳檔案的後臺地址
var form = new FormData() // FormData 物件
form.append('file', fileObj) // 檔案物件
const xhr = new XMLHttpRequest() // XMLHttpRequest 物件
xhr.open('post', url, true) // post方式,url為伺服器請求地址,true 該引數規定請求是否非同步處理。
// xhr.setRequestHeader('Content-Type', undefined)
xhr.onload = (evt) => {
var data = JSON.parse(evt)
if (data.status) {
alert('上傳成功!')
} else {
alert('上傳失敗!')
}
} // 請求完成
xhr.onerror = (x) => {
alert('failed:' + JSON.parse(x))
} // 請求失敗
xhr.onprogress = (x) => {
console.log(`uploading...${x}%`)
} // 請求失敗
xhr.send(form) // 開始上傳,傳送form資料
},
經測試,可以上傳,注意xhr.setRequestHeader('Content-Type', undefined)
被註釋掉了,實際上這時XMLHttpRequest能自動設定content-type,這句加了反倒會報錯。
- jquery
我沒有直接在vue專案中測試jquery,是在一個純靜態html中測試的,使用到了jQuery和query.form外掛:
<!doctype html>
<head>
<title>File Upload Progress Demo #2</title>
<style>
body {
padding: 30px
}
form {
display: block;
margin: 20px auto;
background: #eee;
border-radius: 10px;
padding: 15px
}
.progress {
position: relative;
width: 400px;
border: 1px solid #ddd;
padding: 1px;
border-radius: 3px;
}
.bar {
background-color: #B4F5B4;
width: 0%;
height: 20px;
border-radius: 3px;
}
.percent {
position: absolute;
display: inline-block;
top: 3px;
left: 48%;
}
</style>
</head>
<body>
<h1>File Upload Progress Demo #2</h1>
<code><input type="file" name="myfile[]" multiple></code>
<form action="http://localhost:5000/api/document/test" method="post" enctype="multipart/form-data">
<input type="file" name="files" multiple>
<br>
<input type="submit" value="Upload File to Server">
</form>
<div class="progress">
<div class="bar"></div>
<div class="percent">0%</div>
</div>
<div id="status"></div>
<script src="https://cdn.bootcss.com/jquery/1.7.2/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/jquery.form/3.36/jquery.form.min.js"></script>
<script>
(function () {
var bar = $('.bar');
var percent = $('.percent');
var status = $('#status');
$('form').ajaxForm({
beforeSend: function () {
status.empty();
var percentVal = '0%';
bar.width(percentVal)
percent.html(percentVal);
},
uploadProgress: function (event, position, total, percentComplete) {
var percentVal = percentComplete + '%';
bar.width(percentVal)
percent.html(percentVal);
//console.log(percentVal, position, total);
},
success: function () {
var percentVal = '100%';
bar.width(percentVal)
percent.html(percentVal);
},
complete: function (xhr) {
status.html(xhr.responseText);
}
});
})();
</script>
結果:可以上傳,這個應該沒問題,因為本來就是一個表單上傳啊~~,query.form的作用是使用了一個隱藏的iframe。上傳後重新整理的其實是這個iframe,所以使用者感覺不到頁面重新整理。
雖然實現了,但個人並不喜歡這種hack的寫法。jQuery應該退出歷史舞臺了。也算功成名就。還有,在vue中使用jQuery也不是很難,但總感覺不倫不類。
- 其他庫:
這些庫功能很多,但個人不建議使用,一來很多功能用不上,二來其底層實現不好控制
總結:
我最後選擇了 HTML5 XMLHttpRequest 在asp.net core中上傳檔案,原生模組,靈活方便,隨便就能寫出一個個人定製的不錯的上傳元件。
補充
其實,把上傳的檔案和程式放在同一個伺服器不是很好的做法,完全可以建一個資源伺服器進行隔離,以下是用 express和multer建立的一個簡單上傳檔案後臺:
var express = require('express')
var multer = require('multer')
var upload = multer({ dest: 'uploads/' })
var app = express()
//allow custom header and CORS
app.all('*',function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');
if (req.method == 'OPTIONS') {
res.send(200); //讓options請求快速返回/
}
else {
next();
}
});
app.post('/profile', upload.single('file'), function (req, res, next) {
const file = req.file
const body = req.body
res.send('ok,uploaded')
next()
// req.body will hold the text fields, if there were any
})
app.post('/photos/upload', upload.array('photos', 12), function (req, res, next) {
// req.files is array of `photos` files
// req.body will contain the text fields, if there were any
})
var cpUpload = upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }])
app.post('/cool-profile', cpUpload, function (req, res, next) {
// req.files is an object (String -> Array) where fieldname is the key, and the value is array of files
//
// e.g.
// req.files['avatar'][0] -> File
// req.files['gallery'] -> Array
//
// req.body will contain the text fields, if there were any
})
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
});
這樣,上傳檔案到這個伺服器後,拿到檔案地址,再回來應用插入到資料庫就行
當然,如果資料保密度不高,那用七牛是最簡單的了
最近有個想法,出一個vue+core的工程管理系統(PMS)系列教程,各位喜歡就點個贊吧,我看著贊多了就開始寫(_)
相關文章
- php大檔案上傳注意事項PHP
- SpringMvc 檔案上傳注意事項SpringMVC
- ASP.NET Core 檔案上傳ASP.NET
- ASP.NET 2.0 多檔案上傳小經驗ASP.NET
- [譯]ASP.NET Core 2.0 本地檔案操作ASP.NET
- ASP.NET Core 上傳檔案到共享資料夾ASP.NET
- .Net上傳檔案處理三大正規化,及開發注意事項
- 學習ASP.NET Core Blazor程式設計系列十七——檔案上傳(上)ASP.NETBlazor程式設計
- 用VSCode開發一個asp.net core2.0+angular5專案(5): Angular5+asp.net core 2.0 web api檔案上傳VSCodeASP.NETAngularWebAPI
- .NET Core 如何上傳檔案及處理大檔案上傳
- 檔案上傳那些事兒
- ASP.NET Core檔案上傳IFormFile於Request.Body的羈絆ASP.NETORM
- 學習ASP.NET Core Blazor程式設計系列二十——檔案上傳(完)ASP.NETBlazor程式設計
- 學習ASP.NET Core Blazor程式設計系列十八——檔案上傳(中)ASP.NETBlazor程式設計
- 學習ASP.NET Core Blazor程式設計系列十九——檔案上傳(下)ASP.NETBlazor程式設計
- vue中 靜態檔案引用注意事項Vue
- fgets讀取檔案時的注意事項
- [譯]ASP.NET Core 2.0 機密配置項ASP.NET
- [譯]ASP.NET Core 2.0 全域性配置項ASP.NET
- Asp.net中關於上傳檔案的各項基本操作ASP.NET
- 用ASP.NET上傳大檔案ASP.NET
- 簡單介紹ASP.NET Core實現檔案上傳和下載ASP.NET
- 部署專案注意事項
- 將WAV檔案做到EXE檔案的方法及注意事項 (轉)
- 檔案上傳需要注意的問題
- Laravel 專案上線的一些注意事項Laravel
- 分享一個 asp.net core 多檔案分塊同時上傳的元件ASP.NET元件
- Asp.Net 上傳大檔案專題(1)--概述:上傳大檔案的難點ASP.NET
- ASP.NET Core 配置檔案ASP.NET
- ASP.NET Core - 入口檔案ASP.NET
- .Net Core使用HttpClient請求Web API注意事項HTTPclientWebAPI
- .NET Core Web APi大檔案分片上傳研究WebAPI
- Asp.Net音訊檔案上傳和播放ASP.NET音訊
- asp.net 上傳大檔案大小控制方案ASP.NET
- php檔案上傳之多檔案上傳PHP
- Linux中如何刪除檔案?注意事項有哪些?Linux
- 用IDA匯出map檔案時的注意事項
- Roll-out 專案注意事項