How can I make a response cachable by browsers? I am working on a Drupal Controller implementation that would return a generated image as response. I used Symfony's Response and I was trying to add ETag header to it:

use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class MyController extends ControllerBase {

  public static function viewGraph(string $id, Request $request) {
    $response = new Response();
    $response-&gt;setEtag($etag); // some etag genrated from $id
    if ($response-&gt;isNotModified($request)) {
      return $response;
    }
    // ...
    return $response;
  }

}



I expected to see the "ETag" header in my response. But there is nothing. I've even tried CacheableResponse and it didn't work as well.

What's wrong with my approach? What is the right approach to it?
FinishResponseSubscriber overwrites the ETag header, unless your response meets certain conditions. That is it has to be cacheable and provides a custom Cache-Control header. When testing the code make sure you have browser caching enabled (in the performance settings).

Example:

  public function view() {
    $response = new CacheableResponse();
    $response-&gt;headers-&gt;set('Cache-Control', 'public, max-age=60');
    $response-&gt;setEtag('123'); 
    return $response;
  }


Besides browser caching you might also want to set Drupal caching data to invalidate the cached response when the content becomes outdated, see for example Invalidate cache on a REST endpoint.