Problem with res.set("Content-Type", contentType);

i am having trouble here, it is that when i click on the anchor tag the file is downloaded but when i open it.it always says file type not supported.
here is the react and backend codes respectively.
react

import { useState, useEffect, useContext } from "react";
import axios from "axios";
import { UserContext } from "../App.jsx";
import { useLocation, useOutletContext } from "react-router-dom";

function Class() {
  const location = useLocation();
  const [showForm, setShowForm] = useState(false);
  const [link, setLink] = useState({url: '',filename:'',description: ''});
  const [selected, setSelected] = useState(null);
  const [data, setData] = useState([]);
  const { state, dispatch } = useContext(UserContext);
  const { setMsg } = useOutletContext();

  useEffect(() => {
    axios
      .post("http://localhost:5000/user/subjects/find", {
        fullName: state.name,
      })
      .then((res) => {
        setData(res.data.subjects);
      })
      .catch((err) => console.log(err));
    setMsg(location.state?.msg);
  }, []);

  function handleClick(i) {
    setShowForm(true);
    setSelected(i);
    axios
      .post("http://localhost:5000/user/find/upload", {
        fullName: state.name, subject: data[i] 
      })
      .then((res) => {
        const fileData = res.data.fileData;
      const description = res.data.description;
      const filename = res.data.filename;
console.log(filename,description);
      // Create a blob URL for the file data
      const blob = new Blob([fileData], { type: "application/octet-stream" });
      const url = URL.createObjectURL(blob);
      const newObj = {...link};
      newObj.url = url;
      newObj.filename = filename;
      newObj.description = description;
      setLink(newObj);
      // Create a link to download the file
      // const link = document.createElement("a");
      // link.href = url;
      // link.download = data[i]; // Assuming the file name is the same as the subject
      // document.body.appendChild(link);
      // link.click();
      // document.body.removeChild(link);

      // Handle the description
      console.log(description);
      })
      .catch((err) => console.log(err));
  }

  return (
    <div className="w-full flex justify-evenly">
      {data.map((sub, i) => {
        return (
          <button type="submit"
          className={`text-white ${i === selected?`bg-green-600`:`bg-blue-600`} border h-10 w-1/3 py-2 rounded-md`}
          onClick={(e) => handleClick(i)} key={i}>
            {sub}
          </button>
        );
      })}
      {link.url && 
      <div>
        <div>{link.description}</div>
      <a download={`${link.filename}`} href={link.url}>{link.filename}</a>
      </div>}
    </div>
  );
}

export default Class;

backend

router.route("/class/upload").post(upload.single("file"), async (req, res) => {
  try {
    const {
      batch,
      department,
      stream,
      fullName,
      classId,
      subject,
      description,
    } = req.body;
    const teacher = await User.findOne({ fullName });
    const teacherId = teacher._id;
    console.log({ file: req.file, teacher, classId });
    const file = new File({
      batch,
      department,
      stream,
      classId,
      teacherId,
      subject,
      description,
      filename: req.file.filename,
      path: req.file.path,
    });
    await file.save();

    res.json({ success: true });
  } catch (error) {
    console.error(error);
    res.status(500).json({ success: false, error: "Unable to upload file" });
  }
});

router.post("/find/upload", async (req, res) => { 
  try {
    const { fullName, subject } = req.body;
    const user = await User.findOne({ fullName });
    const findSem = await Class.find({
      batch: user.batch,
      department: user.department,
      stream: user.stream,
      students: user._id,
    });
    if (findSem.length === 1) {
      semester = 1;
    } else if (findSem.length === 2) {
      semester = 2;
    }
    const findClass = await Class.findOne({
      batch: user.batch,
      department: user.department,
      stream: user.stream,
      students: user._id,
      semester,
    });
    const arr = findClass.teacher[semester];
    const filtarr = arr.filter((a) => a.subject.includes(subject));
    console.log(filtarr);

    const file = await File.findOne({
      batch: user.batch,
      department: user.department,
      stream: user.stream,
      teacherId: filtarr[0]?.teacherId,
      classId: findClass._id,
      subject,
    });
    const filePath = path.join(__dirname, "uploads", file.filename);
    fs.readFile(filePath, (err, data) => {
      if (err) throw err;
      const contentType = file.contentType || "application/octet-stream";
      res.set("Content-Type", contentType);
      const description = file.description;
      const filename = file.filename;
      res.json({ success: true, fileData: data, description, filename });
    });

    
  } catch (error) {
    console.error(error);
    res
      .status(500)
      .json({ success: false, error: "Unable to share the file and its " });
  }
});

Shouldn’t you be using data and not file inside the readFile callback?

well data is just a buffer,when i console.log the data this is what i get

<Buffer 25 50 44 46 2d 31 2e 35 0d 0a 25 b5 b5 b5 b5 0d 0a 31 20 30 20 6f 62 6a 0d 0a 3c 3c 2f 54 
79 70 65 2f 43 61 74 61 6c 6f 67 2f 50 61 67 65 73 20 32 20 ... 21426 more bytes>

if i console.log the data.contentType it is undefined.

fs.readFile(path[, options], callback)

If no encoding is specified, then the raw buffer is returned.

In any case findOne does not return a file.


I would suggest using something like multer for file uploads

1 Like

sorry for the late reply,
but i was trying to figure out to fix this. i already set up multer for that i did not include that because i thought you would notice that from the upload.single("file") part

but incase of a need, here it is

const multer = require("multer");
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, path.join(__dirname, "uploads/"));
  },
  filename: function (req, file, cb) {
    cb(null, file.originalname);
  },
});
const upload = multer({ storage });

i have set encoding type as string ‘utf8’,here is the updated code ,but i am only getting [object Object] when i console.log the data and in the front end after downloading the file and opening it i get an error.

router.post("/find/upload", async (req, res) => {
  try {
    const { fullName, subject } = req.body;
    const user = await User.findOne({ fullName });
    const findSem = await Class.find({
      batch: user.batch,
      department: user.department,
      stream: user.stream,
      students: user._id,
    });
    if (findSem.length === 1) {
      semester = 1;
    } else if (findSem.length === 2) {
      semester = 2;
    }
    const findClass = await Class.findOne({
      batch: user.batch,
      department: user.department,
      stream: user.stream,
      students: user._id,
      semester,
    });
    const arr = findClass.teacher[semester];
    const filtarr = arr.filter((a) => a.subject.includes(subject));
    console.log(filtarr);

    const file = await File.findOne({
      batch: user.batch,
      department: user.department,
      stream: user.stream,
      teacherId: filtarr[0]?.teacherId,
      classId: findClass._id,
      subject,
    });
    const filePath = path.join(__dirname, "uploads", file?.filename);
    fs.readFile(filePath,'utf8', (err, data) => {
      if (err) throw err;
      console.log(data);
      const contentType = file.contentType || "application/octet-stream";
      res.set("Content-Type", contentType);
      const description = file.description;
      const filename = file.filename;
      res.json({ success: true, fileData: data, description, filename });
    });
  } catch (error) {
    console.error(error);
    res
      .status(500)
      .json({
        success: false,
        error: "Unable to share the file and its description",
      });
  }
});

I doubt I can figure it out just by looking at a small section of static code. Maybe if you posted the repo people would be able to help you better.


I have done file upload 3 times and it was a hundred years ago. I don’t remember much of it.

I don’t even know if the upload is working as intended. Does the file get saved properly? Can you open it up from the folder?

I don’t really know why you need the file blob code or why you need to set the content type on the file like you are. I also, don’t think you can res.json file data. You can send the data using res.send or res.sendFile. But I don’t see how it would work as JSON sending binary data files.

well, this has given me clues. i checked the file in the upload folder and they would not open all i see is [object Object],i fix that by appending Date.now to the file name when initializing storage for multer and i think it is neccessary, they have mentioned it on the link you give me,their way is incorrect in my view and try,why because they are appending the Date.now and random number generation to the end of the filename which causes error,because it will modify the file extension,so should be at the begining like this:

const multer = require("multer");
const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, path.join(__dirname, "uploads/"));
  },
  filename: function (req, file, cb) {
    cb(null,  Date.now() + '-' + file.originalname );
  },
});
const upload = multer({ storage });

with that i can see the image right opening it in the uploads folder ,but if it is pdf it just simply shows a random strings(i have no idea why?)
well,now i am struggling on how to send back the file to the react application,so that it is downloadable.

well i tried that but the file is still not opening it just says it looks like we do not support this file format,now i am seeing a YT video of using res.download to do that using the npm package js file download.

Are you logging it? I meant just open the file like you would any other file using the OS. You can also inspect the actual file header (hex or some other tool) the start of the file will have metadata about the file type.

DiskStorage

Note: Multer will not append any file extension for you, your function should return a filename complete with an file extension.

res.download is an Express method, you do not need any package for that. Pretty sure you can do the same using send/sendFile but you have to set the Content-Disposition to attachment yourself. It all depends on if you want the file to open in the browser or always just download it. There are also streams as an option but they are more involved (relevant for large files).

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.