# HTTP Response Header for static content

**URL:** <https://discourse.nodered.org/t/http-response-header-for-static-content/84605>\
**Category:** General\
**Created:** [16 January 2024 13:05 UTC](https://discourse.nodered.org/t/http-response-header-for-static-content/84605 "2024-01-16T13:05:39Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![crispy](https://avatars.discourse-cdn.com/v4/letter/c/e47774/32.png) [@crispy](https://discourse.nodered.org/u/crispy)\
**Post date:** [16 January 2024 13:05 UTC](https://discourse.nodered.org/t/http-response-header-for-static-content/84605/1 "2024-01-16T13:05:39Z")

</div>

Hi all,

I have a working flow that serves a page of HTML in response to a GET request. The HTML references some images that I have in a 'images' directory in the location configured in settings.js (/home/username/.node-red/node-red-static/). This all works as expected.

Except....I've been trying to preload images as I have a background image that changes periodically and want it to transition smoothly rather than line-by-line, etc, as sometimes happens, and discover that the content (image) is not being cached when preloaded and an inspection of the headers shows the following (example related to one of the images, but actually they all show the same):

Cache-Control: public, max-age=0

I've found a few articles about setting response headers using code in a function node (eg [Setting headers with "HTTP Response" node](https://discourse.nodered.org/t/setting-headers-with-http-response-node/30719)) but this would appear to be relevant only for content served by a node and not served from the static folders.

Is anyone able to help with setting the Cache-Control header for static content?

Thanks

Chris

---

<div class="post-metadata">

**Author:** ![GogoVega](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/gogovega/32/71313_2.png) [@GogoVega](https://discourse.nodered.org/u/GogoVega)\
**Post date:** [16 January 2024 13:30 UTC](https://discourse.nodered.org/t/http-response-header-for-static-content/84605/2 "2024-01-16T13:30:54Z")

</div>

Hi,  
The `max-age=N` response directive indicates that the response remains [fresh](https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching#fresh_and_stale_based_on_age) until _N_ seconds after the response is generated.

So increment the `max-age`

 ![Capture d’écran 2024-01-16 à 14.28.31](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/9/7/97cd9ab0d389fee3be25bf36c496fe2f34e6b423.png)

---

<div class="post-metadata">

**Author:** ![crispy](https://avatars.discourse-cdn.com/v4/letter/c/e47774/32.png) [@crispy](https://discourse.nodered.org/u/crispy)\
**Post date:** [16 January 2024 14:44 UTC](https://discourse.nodered.org/t/http-response-header-for-static-content/84605/3 "2024-01-16T14:44:43Z")

</div>

Thanks for the reply GogoVega,

I understand the need to increment max-age but where do I find that screen in relation to content served from the node-red-static folder?

---

<div class="post-metadata">

**Author:** ![GogoVega](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/gogovega/32/71313_2.png) [@GogoVega](https://discourse.nodered.org/u/GogoVega)\
**Post date:** [16 January 2024 14:56 UTC](https://discourse.nodered.org/t/http-response-header-for-static-content/84605/4 "2024-01-16T14:56:29Z")

</div>

With:

```js
httpStatic: [
    {
            path: '/opt/static/',
            root: '/private/',
            middleware: myCustomHttpMiddleware
    }
]

```

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [16 January 2024 14:57 UTC](https://discourse.nodered.org/t/http-response-header-for-static-content/84605/5 "2024-01-16T14:57:08Z")

</div>

The httpStatic entries can have a `middleware`

you could try adding a custom middleware for your images

in settings.js

```auto
const cacheControlMiddleware = (req, res, next) => {
  const ext = path.extname(req.url);

  // Check if the request is for JPG or PNG images
  if (ext === '.jpg' || ext === '.png') {
    // Set Cache-Control header for images
    res.setHeader('Cache-Control', 'public, max-age=86400');
  }

  // Continue to the next middleware
  next();
};

...

httpStatic: [
  { ..., middleware: [cacheControlMiddleware] }
]

```

☝ 100% untested and probably needs work - consider it an illustration only ☝

---

<div class="post-metadata">

**Author:** ![crispy](https://avatars.discourse-cdn.com/v4/letter/c/e47774/32.png) [@crispy](https://discourse.nodered.org/u/crispy)\
**Post date:** [16 January 2024 14:59 UTC](https://discourse.nodered.org/t/http-response-header-for-static-content/84605/6 "2024-01-16T14:59:19Z")

</div>

Thanks again...I assume that code gets added to settings.js?

And then the screen you captured appears in the editor somewhere?

Apologies if I'm missing something obvious but I'm not really understanding. Will attempt to add it to settings.js and see whether next steps become obvious.

Thanks again

---

<div class="post-metadata">

**Author:** ![crispy](https://avatars.discourse-cdn.com/v4/letter/c/e47774/32.png) [@crispy](https://discourse.nodered.org/u/crispy)\
**Post date:** [16 January 2024 15:01 UTC](https://discourse.nodered.org/t/http-response-header-for-static-content/84605/7 "2024-01-16T15:01:05Z")

</div>

Thanks Steve-mcl....this looks like it ties in with GogoVega's suggestions - will do some experimenting as this is an area I've had no previous experience in or even tinkered with. Thanks again

---

<div class="post-metadata">

**Author:** ![GogoVega](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/gogovega/32/71313_2.png) [@GogoVega](https://discourse.nodered.org/u/GogoVega)\
**Post date:** [16 January 2024 15:01 UTC](https://discourse.nodered.org/t/http-response-header-for-static-content/84605/8 "2024-01-16T15:01:19Z")

</div>

The image is an example of the http node.  
Here you have to do it in the settings file by combining Steve's message and mine

```js
httpStatic: [
    {
            path: '/home/username/.node-red/node-red-static/',
            root: '/static/',
            middleware: function (req, res, next) {
                const ext = path.extname(req.url);

                // Check if the request is for JPG or PNG images
                if (ext === '.jpg' || ext === '.png') {
                    // Set Cache-Control header for images
                    res.setHeader('Cache-Control', 'public, max-age=86400');
                }

                // Continue to the next middleware
                next();
            }
    }
]

```

Like Steve said, it's not sure to work

---

<div class="post-metadata">

**Author:** ![UnborN](https://avatars.discourse-cdn.com/v4/letter/u/4491bb/32.png) [@UnborN](https://discourse.nodered.org/u/UnborN)\
**Post date:** [16 January 2024 15:22 UTC](https://discourse.nodered.org/t/http-response-header-for-static-content/84605/9 "2024-01-16T15:22:26Z")

</div>

Do you also need to require `path` in order to use it ?

`const ext = require('node:path').extname(req.url);`

---

<div class="post-metadata">

**Author:** ![GogoVega](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/gogovega/32/71313_2.png) [@GogoVega](https://discourse.nodered.org/u/GogoVega)\
**Post date:** [16 January 2024 15:25 UTC](https://discourse.nodered.org/t/http-response-header-for-static-content/84605/10 "2024-01-16T15:25:01Z")

</div>

I don't know 🤷‍♂️

You can use too:

```js
if (req.url.endsWith('.jpg') || req.url.endsWith('.png')) { ... }

```

---

<div class="post-metadata">

**Author:** ![crispy](https://avatars.discourse-cdn.com/v4/letter/c/e47774/32.png) [@crispy](https://discourse.nodered.org/u/crispy)\
**Post date:** [16 January 2024 15:55 UTC](https://discourse.nodered.org/t/http-response-header-for-static-content/84605/11 "2024-01-16T15:55:44Z")

</div>

Thanks again everyone, for your time and effort, I clearly have some reading to do - all I appear to be able to do so far is stop Node-RED from starting at all.

I've reverted everything so I have a working setup but clearly need to do some reading so will do that and continue to experiment.

Updates if I make progress....\>

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [16 January 2024 16:33 UTC](https://discourse.nodered.org/t/http-response-header-for-static-content/84605/12 "2024-01-16T16:33:09Z")

</div>

I believe that the correct method is to use `req.get('Content-Type')` which should return the mime type of the requested resource. This should be, at least in part, independent of the file name and particularly the file extension. It also doesn't need to require the path library.

OK, I think the above is out of date (though probably still works). You should use:

[`req.is(....)`](https://expressjs.com/tr/api.html#req.is)

Or you can use `req.headers['content-type']`

---

<div class="post-metadata">

**Author:** ![crispy](https://avatars.discourse-cdn.com/v4/letter/c/e47774/32.png) [@crispy](https://discourse.nodered.org/u/crispy)\
**Post date:** [16 January 2024 19:40 UTC](https://discourse.nodered.org/t/http-response-header-for-static-content/84605/13 "2024-01-16T19:40:47Z")

</div>

So, thanks again...I've made SOME progress:

with the following in settings.js I get the required Cache-Control header BUT I get it for everything (which is actually fine for my purposes but now that I've seen what you were all trying to do above I want to crack it for the images alone and it seems to be the condition that is breaking it)

```auto
httpStatic: [
  {
    path: '/home/username/.node-red/node-red-static/',
    root: '/static/',
    middleware: function (req, res, next) {
      // Set Cache-Control header for images
      res.setHeader('Cache-Control', 'public, max-age=86400');

      // Continue to the next middleware
      next();
    }
  }
],

```

Unfortunately, when I add in the condition using GogoVega's "endsWith" or "path.extname" examples Node-RED will not restart. I am still working on understanding enough about TotallyInformation's suggestion to write something based on that but am working on it.

---

<div class="post-metadata">

**Author:** ![crispy](https://avatars.discourse-cdn.com/v4/letter/c/e47774/32.png) [@crispy](https://discourse.nodered.org/u/crispy)\
**Post date:** [16 January 2024 19:47 UTC](https://discourse.nodered.org/t/http-response-header-for-static-content/84605/14 "2024-01-16T19:47:00Z")

</div>

Well I don't know what I was doing above because the following is now working but wasn't before, and I can't reproduce the issue - must have been a stray comma or similar

```auto
      httpStatic: [
        {
          path: '/home/username/.node-red/node-red-static/',
          root: '/static/',
          middleware: function (req, res, next) {
            if (req.url.endsWith('.jpg') || req.url.endsWith('.png')) {
              // Set Cache-Control header for images
              res.setHeader('Cache-Control', 'public, max-age=86400');
            }
            // Continue to the next middleware
            next();
          }
        }
      ],

```

and is caching only JPGs and PNGs from the static folder.

Thanks again all, very much, for your input - working solution and learned something new too!

(Still haven't understood enough about req.is() to get that working, sorry TotallyInformation - maybe I'll try again later)

---

<div class="post-metadata">

**Author:** ![GogoVega](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/gogovega/32/71313_2.png) [@GogoVega](https://discourse.nodered.org/u/GogoVega)\
**Post date:** [16 January 2024 19:59 UTC](https://discourse.nodered.org/t/http-response-header-for-static-content/84605/15 "2024-01-16T19:59:44Z")

</div>

In fact what Julian says is to search for the content type from the header instead of using the file name.

Look at [What are all the possible values for HTTP "Content-Type" header? - Stack Overflow](https://stackoverflow.com/questions/23714383/what-are-all-the-possible-values-for-http-content-type-header)

---

<div class="post-metadata">

**Author:** ![crispy](https://avatars.discourse-cdn.com/v4/letter/c/e47774/32.png) [@crispy](https://discourse.nodered.org/u/crispy)\
**Post date:** [16 January 2024 20:09 UTC](https://discourse.nodered.org/t/http-response-header-for-static-content/84605/16 "2024-01-16T20:09:58Z")

</div>

Thanks, yes I understood that from the information in the page he linked. I think the reason it isn't working for me is that I don't know what the 'type' should be - for html it would clearly be 'text/html' but for a JPG I've tried 'image/jpg' and 'image' but neither work.

What should the content type be in the request header for my JPGs? Or, how can I find that? I found the Cache-Control info by inspecting the response headers in Google Chrome's "inspect" feature but am not seeing anything for content-type in the request headers in the same tool.

---

<div class="post-metadata">

**Author:** ![GogoVega](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/gogovega/32/71313_2.png) [@GogoVega](https://discourse.nodered.org/u/GogoVega)\
**Post date:** [16 January 2024 20:14 UTC](https://discourse.nodered.org/t/http-response-header-for-static-content/84605/17 "2024-01-16T20:14:20Z")

</div>

Strange, `jpeg` exists but not `jpg` 😅

 ![Capture d’écran 2024-01-16 à 21.15.28](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/a/1/a15751796ee35e5f6ccc1a457dedba1b054c8921.png)

Maybe linked

---

<div class="post-metadata">

**Author:** ![crispy](https://avatars.discourse-cdn.com/v4/letter/c/e47774/32.png) [@crispy](https://discourse.nodered.org/u/crispy)\
**Post date:** [16 January 2024 20:16 UTC](https://discourse.nodered.org/t/http-response-header-for-static-content/84605/18 "2024-01-16T20:16:08Z")

</div>

Ah!

Does that mean it won't match or that I should use jpeg to match my JPGs? I'll try...

---

<div class="post-metadata">

**Author:** ![crispy](https://avatars.discourse-cdn.com/v4/letter/c/e47774/32.png) [@crispy](https://discourse.nodered.org/u/crispy)\
**Post date:** [16 January 2024 20:16 UTC](https://discourse.nodered.org/t/http-response-header-for-static-content/84605/19 "2024-01-16T20:16:48Z")

</div>

Sorry, just seen your updated message. I will try and see if they are linked and that image/jpeg works with my .jpg files

---

<div class="post-metadata">

**Author:** ![crispy](https://avatars.discourse-cdn.com/v4/letter/c/e47774/32.png) [@crispy](https://discourse.nodered.org/u/crispy)\
**Post date:** [16 January 2024 20:26 UTC](https://discourse.nodered.org/t/http-response-header-for-static-content/84605/20 "2024-01-16T20:26:51Z")

</div>

Hmmmm, well I can't get that working with 'image/jpeg' either. It does work with the

```auto
req.url.endsWith('.jpg')

```

however, so I will keep it configured that way and maybe return to this as a learning opportunity later.

Thanks, all, for your input and time.

[Next page](https://discourse.nodered.org/t/http-response-header-for-static-content/84605.md?page=2)
