Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Upload PDF file to Express server

I've built a basic browser form allowing users to upload a PDF file. I then want to send that file to an Express backend. It seems like this should be a pretty basic action, but I'm unfamiliar with the end-to-end process so I'm not sure which piece is failing. I've searched through a number of SO questions/answers, but haven't found any that provide a complete solution, and I haven't been able to cobble together a solution either.

Update: It looks like the file is getting to the server, but the encoding is messed up. My guess is that FileReader.readAsText is the wrong method to use. FileReader.readAsBinaryString got me a little closer, but still not quite right (and it's deprecated). FileReader.readAsArrayBuffer seems like potentially the way to go, but I'm not sure how to correctly handle the buffer in Express.

Client/Browser

The form is built in React and just uses an onChange handler on the input itself. When a file has been added, the handler reads the file, adds it to the form data and sends the post request to the server.

// React form
<input
  name="upload"
  onChange={this._handleUpload}
  type="file"
/>

_handleUpload = (e) => {
  const { files, name } = e.target;

  // Read the file
  const reader = new FileReader();
  reader.onload = (e) => {
    const file = e.target.result;

    // Now that we have the file's contents, append to the form data.
    const formData = new FormData();
    formData.append('file', file);
    formData.append('type', name);

    axios
      .post('/upload', formData)
      .then(res => {
        // Handle the response...
      })
      .catch(err => console.log(err));
  };

  // Reading as text. Should this be something else?
  reader.readAsText(files[0]);
}

Express App

The express app uses multer middleware to process the upload:

const app = express();
const upload = multer({});

app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cors());
app.post('/upload', upload.any(), handleUpload);

Middleware

Finally, I have my own middleware that gets the file from multer. I'm testing this piece by just writing the file I've received to disk. It has contents, but it's not a readable PDF file.

const handleUpload = (req, res, next) => {
  // The file shows up on req.body instead of req.file, per multer docs.
  const { file } = req.body;

  // File is written, but it's not a readable PDF.
  const tmp = fs.writeFileSync(
    path.join(__dirname, './test.pdf'),
    file,
  );
}

Is there some piece that I'm getting obviously wrong here? eg: Do PDFs need to be handled in a special way? Any tips for where to focus my debugging?

like image 321
ericgio Avatar asked Dec 15 '18 00:12

ericgio


People also ask

Can I upload a PDF into WordPress?

Uploading PDF files in WordPress is similar to uploading images and other media files on your website. To get started, login to your WordPress admin area and then go to Media. After that, click the “Add New” button. Simply drag and drop your PDF file in WordPress or click the “Select Files” button to upload it.


1 Answers

See if that solves your problem.

_handleUpload = (e) => {
    const dataForm = new FormData();
    dataForm.append('file', e.target.files[0]);  
      axios
        .post('http://localhost:4000/test', dataForm)
        .then(res => {

        })
        .catch(err => console.log(err));      
}

render() {
  return (
    <div className="App">
      <input
      onChange={this._handleUpload}
      type="file"
      />    
    </div>
  )
}

server:

router.post('/test', upload.any(), (req, res) => {
    console.log(req.files)
    res.send({sucess: true})
})

No need to send the file type, the multer identifies the name and type for you.

like image 141
Chance Avatar answered Nov 11 '22 10:11

Chance