TeabagD
TeabagD

Reputation: 659

Piping (proxying) an image stream in express produces an empty box

I am trying to pipe an image response from an internal API, using NodeJS Express to an external endpoint. I.e. proxying an image.

This is what I have tried, but I keep getting an empty box instead of the image:

app.get('/image', (req, res) => {
    res.setHeader('Content-Type', 'image/png');
    request.get(`http://localhost:8080/image`).pipe(res);
    
    // Also tried reading from a file and not the endpoint 
    //to make sure it's not a problem  with "request" library with same results
    //fs.createReadStream('./image.png').pipe(res);
});

Using browser dev tools I can also see that the size of the empty image I get on the external endpoint is bigger then that of the working image got from the internal endpoint.

Accessing the endpoint from "Postman" seems to give the image without problems, but accessing from Firefox says that the image has errors.

So it seems to be some kind of an encoding issue which I can't seem to figure out how to fix. Please help.

Upvotes: 0

Views: 1780

Answers (2)

TeabagD
TeabagD

Reputation: 659

Thank you slideshowp2 for taking your time and pointing out that, my provided code should indeed work.

It would have been impossible to figure out the issue with the info that I gave.

I was using "livereload" middleware in my project.

This middleware intersects all the responses coming from my server and tries to inject the liverelad script into them.

By default it is configured to ignore responses for endpoints ending with ".png" and other image and binary formats.

Adding ".png" to the endpoint path, solved the issue.

app.get('/image.png', (req, res) => {
    request.get(`http://localhost:8080/image`).pipe(res);
});

Upvotes: 0

Lin Du
Lin Du

Reputation: 102527

Can't reproduce your issue. The below example works fine. Testing environment:

  • Microsoft Edge 86.0.622.38

E.g.

server-internal.ts:

import express from 'express';
import fs from 'fs';
import path from 'path';

const app = express();
const port = 8080;

app.get('/image', (req, res) => {
  console.log('internal server /image');
  res.setHeader('Content-Type', 'image/png');
  fs.createReadStream(path.resolve(__dirname, './image.png')).pipe(res);
});

app.listen(port, () => console.log('HTTP server is listening on port:', port));

server-external.ts:

import express from 'express';
import request from 'request';

const app = express();
const port = 3000;

app.get('/image', (req, res) => {
  console.log('external server /image');
  res.setHeader('Content-Type', 'image/png');
  request.get(`http://localhost:8080/image`).pipe(res);
});

app.listen(port, () => console.log('HTTP server is listening on port:', port));

Access http://localhost:3000/image, got the image correctly.

The logs of the internal server:

HTTP server is listening on port: 8080
internal server /image

The logs of the external server:

HTTP server is listening on port: 3000
external server /image

source code: https://github.com/mrdulin/expressjs-research/tree/master/src/stackoverflow/64302729

Upvotes: 1

Related Questions