The foreword 0.

Recently, I made a lot of mistakes while uploading pictures to the server and displaying them. So, wrote this article, to record these days to step on the pit. The technology stack used for uploading images is:

  • Front end: React; Axios is used to send Ajax requests
  • Back-end: Express builds the server; Formidable is used to parse the From form and save the file

1. Pit treading process

1.1. Encountered problems

In order to solve the problem of uploading images to the server, I searched a lot of information on the Internet and finally decided to use the AXIOS library to send Ajax requests on the front end and package the images into the FormData object. On the back end, FORMIDABLE parsed the FormData and saved the files to the static resources folder of Express. The implementation code is as follows:

  • Front-end rendering:
<div>
    <input type="file" name="add-img" ref={this.fileInput}/>
    <input type="button" value="Upload" onClick={this.upload}/>
</div>
Copy the code
  • Front-end acquisition picture:
// Register ref in the react constructor
constructor(props){
    super(props)
    this.fileInput = React.createRef()
}
Copy the code
  • Front-end upload picture:
upload = () = > {
    // console.log(this.fileInput.current.files[0])
    const data = new FormData()
    data.append('imgFile'.this.fileInput.current.files[0])
    console.log(data.get('imgFile'))

    const uploadPicture=(formData) = >{ 
        // The url temporarily uses a front-end proxy across domains
        return axios.post("/api/upload",formData);
    }

    uploadPicture(data)
    .then(response= > {
        console.log(response)
    })
    .catch(err= > {
        throw err
    })
}
Copy the code
  • Backend server register static folder:
app.use('/public', express.static('public'))
Copy the code
  • The back-end server parses the data and saves the file:
app.post('/upload'.(req,res) = > {
    var form = new formidable.IncomingForm()
    var path = require('path')
    form.uploadDir = path.resolve(__dirname,'.. /.. /public')
    console.log(form.uploadDir)
    form.keepExtensions = true
    form.parse(req, (err, fields, files) = > {
        if(err) {
            console.log(err)
            console.log(fields)
            console.log(files)
            res.json({
                'code': 1.'err': err,
            })
        } else {
            res.json({
                'code': 0.'file': files
            })
        }
    })
})
Copy the code

However, after running the front and back end servers, an error occurs when the upload image button is clicked. So BEGAN my long debug journey…

1.2. Analyze the problem

After a lot of digging around, I finally located the problem at the request header when I sent the Ajax request. In my code, the request header changed directly:

const config = {
    headers: {
        'Content-Type': 'multipart/form-data'}}Copy the code

Then, after the first run, an error is reported:

Error in posting multipart/form-data. Content-Type header is missing boundary
Copy the code

So I found a boundary somewhere else and added it after multipart/form-data.

After that, the error continues:

Error: MultipartParser.end(): stream ended unexpectedly: state = START_BOUNDARY
Copy the code

I then try to print the File information and the fields information, and both result in {} empty objects.

After more than a dozen searches, the problem was finally traced to the Content-Type attribute added to the request header.

When uploading the file, set the content-Type of the request header to multipart/form-data and add Boundary as the parsing file Boundary. Otherwise, the back end cannot parse the form data. At this point, the problem becomes how to obtain the correct Boundary.

1.3. Solutions

Finally, I found a solution in a blog post. No more nonsense, paste code:

axios.interceptors.request.use(config= > {    
            let csrfToken = localStorage.getItem("token");   
               config.headers["token"] = csrfToken;   
                if(config.url=="api/upload") {// The content-type of the request header should be multipart/form-data
                    config.headers['Content-Type'] ="multipart/form-data";   
                }else{       
                    config.headers['Content-Type'] = 'application/json';    
               }     
               return config; 
            })  
Copy the code

Just add this code to the upload() function.