node.jsexpressnode-mysql

How do I send a longblob as image/jpeg?


I'm stuck trying to get an express server to answer an image file loaded from a mysql database. All of this is running on a robust AWS EC2 image running Rocky Linux (CentOS8).

I have a jpeg/jpg image stored in mysql as a LONGBLOB.

I describe how I upload and store the image below.

In the node-express implementation of a GET endpoint, I need to send (res.send) the binary data so that a browser renders it as an image.

Here is the URL that the browser requests:

https://my.domain.name:7003/personae/personaPicture?personaPictureID=fb5e2a5e-5996-4055-8e2a-b95707d76eea

In my IDE (VisualStudio code), I have the following:

const imageData = {
  data: (502547) [...<lots of bytes> ],
  type: 'Buffer'
}
const imageType: 'image/jpeg'

Here is endpoint code where I am trying to send the image:

res.type(imageType);
res.send(imageData);

The endpoint returns normally -- here is the console log:

GET /personae/personaPicture?personaPictureID=fb5e2a5e-5996-4055-8e2a-b95707d76eea 200 0.15 ms - 1784290

The result, in Firefox - v110.0 (64-bit) - is a broken image.

In the inspector of the "Developer Tools", when I mouse over the img, it says:

Could not load the image

I've spent the last few hours stepping through the code in res.send. It appears to me that express is turning the imageData (a Buffer) into json. That doesn't sound right.

I've been digging through documentation and a multitude of web sources with no joy.

I'm aware that this may be GIGO issue. The image is uploaded using the file-upload component. The middleware is saving the inbound image as a temporary file:

app.use(fileUpload({
  useTempFiles : true,
  tempFileDir: '/home/tms/tmp',

The POST endpoint that collects the upload looks like:

const image_upload = req.files.image_upload;
const temporaryFilePath = image_upload.tempFilePath;
const imageType = image_upload.mimetype;
const imageSize = image_upload.size;
const imageName = image_upload.name;
const imageEncoding = image_upload.encoding;
const imageMD5 = image_upload.md5;

The values look reasonable to me.

I store these fields in MySQL, and I use the following SQL to store the imageData:

(LOAD_FILE('<temporaryFilePath>'))

That field receiving that value is a LONGBLOB.

I note that value of imageEncoding is 7bit. I don't see that "7bit" encoding anywhere as I step through res.send in the debugger. There are several places in the server code that have an encoding variable, and it's value is never defined.

I've tried fiddling with base64 encoding imageData, and that doesn't seem to help.

With any luck, this is something simple that I've overlooked in the documentation.

I hope this community can help my find the error of my ways.

I appreciate your collective attention.


Solution

  • I have found and solved the problem.

    The problem was that the data I was attempting to send was a literal object rather than an instance of Buffer. Once I see the problem, it is obvious from the code fragment in my original question:

    const imageData = {
      data: (502547) [...<lots of bytes> ],
      type: 'Buffer'
    }
    const imageType: 'image/jpeg'
    

    Here is the code that works in the above example:

    const imageBuffer = Buffer.from(imageData.data);
    res.set('Content-Type', `${imageType}`);
    res.send(imageBuffer);
    

    I saw the "type: Buffer" in the broken code and didn't see the curly braces around the value!

    I appreciate the attention. I'm leaving this question here, and answering it myself, in hopes that it may help other developers who need to do the same thing.