Foreword
In the previous article, Let’s talk about the interaction between front-end and back-end data from the form form, I explained some of the connections between the browser and the server. It seems that I have mastered the form form, but the reality is cruel. , I only discovered in a recent project that there is a large piece of knowledge about the form form, which I just clicked on in the previous article. There are quite a lot of uses for this piece of content, that is, file uploading.
1. FormData
The previous article mentioned that the way to organize the form is to use jquery's serializeArray function, but this method is invalid for input[type="file"], which means that it cannot integrate the contents of the file. Go to the form. For related issues, please refer to jquery’s official issue: https://bugs.jquery.com/ticket/2656. The explanation is:
The serialize method can't get the contents of the file so I don't understand why it would need to serialize the file form field. You'd have to use one of the Ajax File upload plugins to get the contents via AJAX.
So can we get the submitted form without using a plug-in? of course!
1.1. The role of FormData
This is the FormData we want to introduce. According to the MDN explanation of FormData:
The FormData interface provides a simple way to build key-value pairs to represent their fields and values, and can be easily sent to the server through `XMLHttpRequest.send()`. It uses the same format as if the form's encoding type was set to `multipart/form-data`.
FormData objects can be traversed using `for...of` instead of `entries()`: `for (var p of myFormData)` is equivalent to ` for (var p of myFormData.entries()) `
This explanation made me understand at least two points:
FormData can be used to process forms with multipart/form-data encoding types, usually with input[type="file"] form;
The fields in FormData can be checked through for...in. (This object cannot be printed using console.log in the browser)
Then some children will definitely ask:
Use FormData to submit without input[type="file"] type Isn't it possible with forms?
What happens if you use FormData to submit a form without input[type="file"] but using the encoding type x-www-form-urlencoded?
If I don’t use FormData, can’t I submit a form with input[type="file"]?
Then we use demo to explain these two problems:
Yes, the encoding type at this time is multipart/form-data, that is, the form submission method will be roughly like this:
We can see This encoding type makes the form unique. If you use express4 or above on the server side, you need to install additional middleware to handle this type of request, otherwise you will not find any of your form data in req.body, req.param, and req.query. These will be discussed later. So why do we still not advocate using this method to submit those simple forms (this is the case for most websites):
You must have discovered that the form we submitted is just a few characters, but after adding those boundaries, it will cause The form data has become larger, which means that even the most efficient binary encoding takes longer than writing the form data directly to the MIME header!
Tips: However, x-www-form-urlencoded seems a bit difficult to process those non-alphanumeric characters, because the browser will translate those non-alphanumeric characters into %HH, which means that each non-alphanumeric character will be converted by 3 bytes to replace, which is very unfriendly when the form is very long, so multipart/form-data appeared.
To answer the second question, if that is the case, then we can see req.body in the server (express4):
{ '------WebKitFormBoundary5Kj2oSfHZKrZjYjsrnContent-Disposition: form-data; name ': '"user"rnrnddrn------WebKitFormBoundary5Kj2oSfHZKrZjYjsrnContent-Disposition: form-data; name="email"rnrnddddrn------WebKitFormBoundary5Kj2oSfHZKrZjYjs--rn' }
Copy code
Look, this way you let How does the server parse it? ? ? This is just causing trouble for myself.
If you do not use FormData's haunted, it can also be submitted. You can use pure AJAX to achieve it. For specific details, please refer to: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using XMLHttpRequest#Submitting forms and uploading_files
1.2. Conclusion
In summary, when we use a form that contains input[type="file"] or contains many non-alphanumeric characters, we need to use FormData to submit the form and encode it Type must be multipart/form-data. Then the roughly used example is:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>testing form group</title> <script type="text/JavaScript" src="http://cdn.bootcss.com/jquery/3.1.0/jquery.min.js"></script> <script type="text/JavaScript"> function onSubmit(){ var myForm = document.getElementById('form'); var formData = new FormData(myForm); for (var p of formData){ console.log(p); } $.ajax({ type: 'POST', url: '/get', data: formData, dataType: 'json', processData: false, contentType: false, success: function(data){console.log(data)}, error: function(jqXHR){console.log(jqXHR)}, }) } </script> </head> <body> <form action="" method="post" name='info' id='form'> <input type="text" name="user" /> <input type="text" name="email" /> <input type="file" name="file" /> <input type="file" name="file1" /> </form> <button type="button" name='submit' onclick="onSubmit()">提交</button> </body> </html>
Note
We configured processData: false and contentType: false in $.ajax to prevent jquery from further processing the data:
processData (default: true)
Type: Boolean
By default, by The data passed in with the data option, if it is an object (technically speaking, as long as it is not a string), will be processed and converted into a query string to match the default content type "application/x-www-form-urlencoded". Set to false if you want to send DOM tree information or other information that you don't want to convert.
1.3, FormData API
FormData.append(): Append a new value to an existing key or add a new key;
FormData.delete(): Delete a key-value pair
FormData.entries(): Returns an iterator so that the key-value pairs in the object can be traversed
FormData.get(): Returns the value of the first given key
FormData.getAll(): Returns the value of the given key Array of all values
FormData.has(): Determines whether the FormData object has a given key-value pair
FormData.keys(): Returns an iterator to allow iteration of the keys of all key-value pairs
FormData.set( ): Modify the value in an existing key or add a new key-value pair
FormData.values(): Return an iterator to allow traversing the values of all key-value pairs
2. About input[type= "file"]
There are a few points about this type of input that need to be mentioned, otherwise I will forget them next time:
Use the multiple attribute to select multiple files at once, and use the accept attribute to execute the corresponding MIME type.
$(element).files gets a file array. You can get the name of the uploaded file and the number of uploaded files: .name and length.
When it comes to uploading files, sometimes you may need to verify the file name or suffix, then regular expressions come in handy at this time. If you verify a format of xxx-vx.x.{json| yaml} (such as bower-v0.1.json), the regular expression used is:
var reg = /^\w+\-v\d+\.{1}\d+\.(json|yaml)$/i; /*Check if the user has not selected uploaded file*/ if ($(Element).val() === ''){ finalRes.delete('file'); } else { var fileCount = $(Element)[0].files.length; for (var i = 0; i < fileCount; i++) { if (reg.test($(Element)[0].files[i].name )){ console.log('match'); }else{ alert('上传的文件名格式不正确'); return; } } }
Then when removing the suffix, you can use replace(/.(json|yaml)$/, '' ) to remove the suffix. 4. A good function to clear the form is:
function clearAllFields(){ $(':input','#project-info') .not(':button, :submit, :reset, :hidden') .val('') .removeAttr('checked') .removeAttr('selected'); }
Note that
$(element) represents the input tag of the file you uploaded.
finalRes is the form value after your new FormData
3. Express server-side processing
After Express4. Installed. There are many such packages, and I chose to use the multiparty middleware. For specific usage methods, please refer to the official website: https://github.com/expressjs/node-multiparty.
There are two ways to use this middleware:
Use event listening form
Use callback form
I used callback form in the project:
router.post('/get', function(req, res, next) { var form = new multiparty.Form(); form.parse(req, function(err, fields, files) { if (fields === undefined || files === undefined){ console.log('client send empty data in posting new project'); return res.status(200).json({err:"请求数据为空,请重新提交", status:'failure'}); } console.log(fields, files); console.log('Upload completed!'); }); });
In fields and files The fields are organized according to the name you provide in the form. Taking the front-end code in the first section as an example, the result at this time should be:
{ user: [ 'test' ], email: [ 'test1' ] } { file: [ { fieldName: 'file', originalFilename: 'test.html', path: '/home/private/test/QForTTWBipWSPSTpKsUGlRHE.html', headers: [Object], size: 876 } ], file1: [ { fieldName: 'file1', originalFilename: 'test1.html', path: '/home/private/test/aT5T2B_pkkxEVv5OUzjjCxIB.html', headers: [Object], size: 558 } ] }
At this time, the default file has been uploaded to the default file folder, according to the explanation on the official website, if uploadDir is not configured during initialization, it will be uploaded to the system's os.tmpdir().
As for the implementation of event types, it is also similar. You can refer to the demo provided on its official website.