How to do file downloading in a controller function? I asked the question about downloading of files upon submitting a form.

Now I want to clarify how to do it in the case of controller function. 
That is, some controller is called and its function is being executed.

In the form submit function file downloading starts upon executing the $form_state-&gt;setResponse($response);

How to start it in the controller function ? 

I tried to use $response-&gt;send(); but it sends a file with wrong data and another size.
Never send the response with $response-&gt;send(). Instead return the response:

use Symfony\Component\HttpFoundation\Response;

public function myController() {
    $response = new Response();
    // prepare $response
    return $response;
  }


BTW, this is a standard Symfony Controller. The fact that you also can return the main content in a render array is because Drupal has added an event subscriber, which converts the main content to a response with the themed html page.



This works for all responses, in your case for example for a binary file response:

Drupal\system\FileDownloadController::download():

  public function download(Request $request, $scheme = 'private') {
    $target = $request-&gt;query-&gt;get('file');
    // Merge remaining path arguments into relative file path.
    $uri = $scheme . '://' . $target;

    if (file_stream_wrapper_valid_scheme($scheme) &amp;&amp; file_exists($uri)) {
      // Let other modules provide headers and controls access to the file.
      $headers = $this-&gt;moduleHandler()-&gt;invokeAll('file_download', [$uri]);

      foreach ($headers as $result) {
        if ($result == -1) {
          throw new AccessDeniedHttpException();
        }
      }

      if (count($headers)) {
        // \Drupal\Core\EventSubscriber\FinishResponseSubscriber::onRespond()
        // sets response as not cacheable if the Cache-Control header is not
        // already modified. We pass in FALSE for non-private schemes for the
        // $public parameter to make sure we don't change the headers.
        return new BinaryFileResponse($uri, 200, $headers, $scheme !== 'private');
      }

      throw new AccessDeniedHttpException();
    }

    throw new NotFoundHttpException();
  }