This is the 8th day of my participation in Gwen Challenge
Recently just do a requirement, about the file upload, download function, also encountered some pits in the middle, record summary, before writing this function, we need to understand the prior knowledge. The front-end sends a request with parameters, and the server responds to the request and receives parameters. Generally, the encoding mode of the message body is obtained according to the Content-Type field, and then decoded accordingly.
1, before the words,
In the earliest HTTP POST requests, parameters were passed through the browser URL and only supported: Application/X-www-form-urlencoded, which does not support file uploads, content-Type extends the multipart/form-data type to support sending binary data to the server, and later, The evolution of easy-going Web applications has added the Application/JSON type, the most commonly used, for RESTFUL interfaces
2, Content-Typetype
(1) application/x-www-form-urlencoded
For native forms, if encType attribute is not set, data will be submitted in application/ X-www-form-urlencoded mode by default, and the submitted expression data will be converted into key-value pairs. The URL is encoded in the key= Value1&key =value3&key=value3 format. If the URL contains Chinese characters or special symbols, the URL is automatically transcoded. Note: Files are not supported and are generally used for form submission
(2) multipart/form-data
When a form uploads a file, it must set the encType of the form to be equal to the type multipart/form-data. This method is mostly used for file uploading. Boundary is used to separate each form item. Boundary boundary is generally placed after content-Type and transmitted to the server, and the server analyzes data and divides segments according to this boundary.
Connection: keep-alive
Content-Length: 9020
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryujJLO5p0jTkaNNbC
Copy the code
Note: Content-Type indicates that the data is encoded by mutipart/form-data. What is the Content of boundary in this request? The message body is divided into several parts with similar structure according to the number of fields. Each part starts with boundary, and the message body ends with boundary marking
<form action="/" method="post" enctype="multipart/form-data">
<input type="text" name="description">
<input type="file" name="myFile">
<button type="submit">Submit</button>
</form>
Copy the code
(3) application/json
One of the benefits of the JSON format is that it supports structured data that is much more complex than key-value pairs, and the server can handle JSON data very well. Due to the popularity of the JSON specification, Major browsers are starting to support json.stringfy natively. Most RESTFUL apis receive application/ JSON types,
3. Upload and download
This requirement is special: the back end will return me a different data structure. If the file is uploaded successfully and the back end verifies successfully, the interface will return me the following data: JSON, if the file is uploaded successfully, the back end verification fails, the interface returns my data as a binary stream, the front end needs to download it in.xlsx mode, if the file fails to upload, the interface will return a binary stream, if the parsing fails, it will also give an error message
The first step is to download the Excel template, which is relatively easy:
1. Obtain template data from the server:
responseType: 'blob',
Copy the code
2, then encapsulate a download method
/** * description: the first parameter of the blob object is response.data, which represents the file stream returned by the back end. The second parameter sets the file type * response: blob object data * filename: filename */
downloadFileExport(response, filename) {
const contentType = response.type // File type
const blob = new Blob([response], {
type: contentType
})
if ('download' in document.createElement('a')) { // Non-IE download
const linkElement = document.createElement('a') // Create a tag
// Generate download link, this link is directly downloaded on the A tag, put on the IMG can directly display the image price, the same as the video
const url = window.URL.createObjectURL(blob)
linkElement.setAttribute('href', url)
linkElement.setAttribute('target'.'_blank')
linkElement.setAttribute('download', filename)
// Simulate clicking the A TAB
if (typeof MouseEvent === 'function') {
var event = new MouseEvent('click', {
view: window.bubbles: true.cancelable: false
})
linkElement.dispatchEvent(event)
}
} else {
navigator.msSaveBlob(blob, filename)
}
}
Copy the code
3. Template download
Data: Blob data stream retrieved from the back end,const textValue = 'User form.xlsx'
this.downLoadFileExport(data, textValue)
Copy the code
4. File upload
1. The first step is to verify the uploaded files
// Click the download button,
changeFile(file) {
const fileData = file.raw // Get the file contents
if(! fileData)return; // If the file content is empty
// 1
CheckExcel (param) checkExcel(param) checkExcel(param)
// 3, according to the verification results to display
checkExcel(form).then(res= > {
let data = res.data // Get the bloB data stream of the validation result returned by the server
// If the type returned by the backend is JSON, there is no need to download Excel
if(data.type.includes('application/json')) {
var reader = new FileReader(); // FileReader converts the blod stream into a JSON object
reader.onload = (e) = > { // Async function to retrieve the JOSN object
let result = JSON.parse(reader.result);
if (result && result.code == 200) {
// Let the successfully uploaded file be displayed, and only one can be uploaded
this.fileList[0] = {name: file.name, uid: file.uid }
this.$message.success('File uploaded successfully')}else {
this.fileList = []
this.$message.error(result.message)
}
}
reader.readAsText(data, 'utf-8');
}
// If the type returned by the backend is Application /vnd.ms-excel, excel needs to be downloaded
if(data.type.includes('application/vnd.ms-excel')) { // For excel streams
this.fileList = []
this.$message.error('File upload failed')
const textValue = file.name
const blob = new Blob([res.data], {type: "application/vnd.ms-excel; charset=utf-8"})
this.downLoadFileExport(blob, textValue)
}
}).catch(err= > {
this.fileList = []
console.log(err)
})
}
Copy the code
2. The second step is the verification of the document content approval chain
/** * Verify file contents */
checkContent(params).then(res= > {
let checkData = res.data // The backend returns the result of the server verifying the file
// If the result is a JSON object,
if(checkData.type.includes('application/json')) {
var reader = new FileReader();
reader.onload =(e) = > {
let result = JSON.parse(reader.result);
if (result.data && result.code == '200') {
this.approveChainForSubmit = result.data.approvalChain
this.cacheKey = result.data.cacheKey
// Other operations after the data is obtained can be ignored
} else {
this.$message.error(result.message)
}
}
reader.readAsText(checkData, 'utf-8'); // Pay attention to the order
}
// If application/vnd.ms-excel is returned from the backend, the verification fails and you need to download Excel
if(checkData.type.includes('application/vnd.ms-excel')) {
this.$message.error('Approval chain validation failed')
const textValue = this.fileList[0].name
const blob = new Blob([checkData], {type: "application/vnd.ms-excel; charset=utf-8"})
this.downLoadFileExport(blob, textValue)
return new Promise(() = >{}) // Terminate the chain call to. Then, which returns only a pendding promise
}
}).catch(err= > {
console.log(err)
})
Copy the code
4, step on the pit
Here is one of three needs:
1. Event sequence of fileReader objects
ReadAsText (checkData, ‘utF-8 ‘) and read. onload =(e) =>{
Reader.onload
After: reader. ReadAsText
The desired method must be executed after reader.onload to fetch the desired parameter
2, return new Promise(() =>{})
Multiple chain requests, only to one error, to terminate. A chained call to terminate. Then has one and only method that returns a Pendding state promise
3, blob = new blob ([data], filename)
A BLOB, or binary large object, is a container that can store binary files,
A Blob object refers to a sequence of bytes and has the size attribute, which is the total number of bytes in the sequence, and a Type attribute, which is a sequence of media-type bytes represented by a lowercase ASCII encoded string.
Create using the constructor of Blob(). The constructor takes two arguments
The first argument is a sequence of data in the format ArrayBuffer, ArrayBufferView, Blob, or DOMString. The second argument is an object containing the following two propertiesCopy the code
5, DOM code
A quick post on the DOM code
<el-button class="downLoad" @click="downloadTemplate">Download the template</el-button>
<div class="ElFormItem-right">
<el-upload
:auto-upload="false"
:show-file-list="true"
:on-change="changeFile"
:action="upload"
:file-list="fileList"
:on-remove="handleRemove"
accept=".xlsx"
>
<el-button size="mini">Batch upload</el-button>
</el-upload>
</div>
Copy the code
6,
There are many ways to download it, you can also use a third party to work. This article is mainly to record the problems I encountered during the development project. The main problem is that I took a lot of time to step on the pit, the order is not right, the asynchronous events of reader.onload keep going in