diff --git a/core/authorize.php b/core/authorize.php
index ba71c5d..86c1f8d 100644
--- a/core/authorize.php
+++ b/core/authorize.php
@@ -21,6 +21,7 @@
  */
 
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
 
 // Change the directory to the Drupal root.
 chdir('..');
@@ -77,6 +78,7 @@ function authorize_access_allowed() {
 $output = '';
 $show_messages = TRUE;
 
+$response = new Response();
 if (authorize_access_allowed()) {
   // Load both the Form API and Batch API.
   require_once __DIR__ . '/includes/form.inc';
@@ -148,14 +150,13 @@ function authorize_access_allowed() {
   $show_messages = !(($batch = batch_get()) && isset($batch['running']));
 }
 else {
-  drupal_add_http_header('Status', '403 Forbidden');
+  $response->setStatusCode(403);
   watchdog('access denied', 'authorize.php', NULL, WATCHDOG_WARNING);
   $page_title = t('Access denied');
   $output = t('You are not allowed to access this page.');
 }
 
 if (!empty($output)) {
-  drupal_add_http_header('Content-Type', 'text/html; charset=utf-8');
   $maintenance_page = array(
     '#page' => array(
       '#title' => $page_title,
@@ -164,5 +165,7 @@ function authorize_access_allowed() {
     '#content' => $output,
     '#show_messages' => $show_messages,
   );
-  print drupal_render($maintenance_page);
+  $response->setContent(drupal_render($maintenance_page));
+  $response->headers->set('Content-Type', 'text/html; charset=utf-8');
+  $response->send();
 }
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index 61d9fee..27fc912 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -869,8 +869,6 @@ function install_display_output($output, $install_state) {
   // reached in case of an early installer error.
   drupal_maintenance_theme();
 
-  drupal_page_header();
-
   // Prevent install.php from being indexed when installed in a sub folder.
   // robots.txt rules are not read if the site is within domain.com/subfolder
   // resulting in /subfolder/install.php being found through search engines.
@@ -911,7 +909,17 @@ function install_display_output($output, $install_state) {
   if (isset($output['#title'])) {
     $install_page['#page']['#title'] = $output['#title'];
   }
-  print drupal_render($install_page);
+
+  $response = new Response();
+  $default_headers = array(
+    'Expires' => 'Sun, 19 Nov 1978 05:00:00 GMT',
+    'Last-Modified' => gmdate(DATE_RFC1123, REQUEST_TIME),
+    'Cache-Control' => 'no-cache, must-revalidate, post-check=0, pre-check=0',
+    'ETag' => '"' . REQUEST_TIME . '"',
+  );
+  $response->headers->add($default_headers);
+  $response->setContent(drupal_render($install_page));
+  $response->send();
   exit;
 }
 
diff --git a/core/includes/update.inc b/core/includes/update.inc
index 0bca244..f7bd86a 100644
--- a/core/includes/update.inc
+++ b/core/includes/update.inc
@@ -18,6 +18,7 @@
 use Drupal\Component\Uuid\Uuid;
 use Drupal\Component\Utility\NestedArray;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
 
 /**
  * Disables any extensions that are incompatible with the current core version.
@@ -153,13 +154,14 @@ function update_check_requirements($skip_warnings = FALSE) {
     );
     $status_report = drupal_render($status);
     $status_report .= 'Check the messages and <a href="' . check_url(drupal_requirements_url($severity)) . '">try again</a>.';
-    drupal_add_http_header('Content-Type', 'text/html; charset=utf-8');
     $maintenance_page = array(
       '#theme' => 'maintenance_page',
       '#title' => 'Requirements problem',
       '#content' => $status_report,
     );
-    print drupal_render($maintenance_page);
+    $response = new Response(drupal_render($maintenance_page));
+    $response->headers->set('Content-Type', 'text/html; charset=utf-8');
+    $response->send();
     exit();
   }
 }
diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module
index dc06282..8af5663 100644
--- a/core/modules/toolbar/toolbar.module
+++ b/core/modules/toolbar/toolbar.module
@@ -9,6 +9,7 @@
 use Drupal\Core\Language\Language;
 use Drupal\Core\Template\Attribute;
 use Drupal\Component\Utility\Crypt;
+use Symfony\Component\HttpFoundation\JsonResponse;
 use Symfony\Component\HttpFoundation\Response;
 use Drupal\menu_link\MenuLinkInterface;
 use Drupal\user\RoleInterface;
@@ -111,6 +112,9 @@ function toolbar_element_info() {
  *
  * @todo Replace this hack with something better integrated with DrupalKernel
  *   once Drupal's page caching itself is properly integrated.
+ *
+ * @return \Symfony\Component\HttpFoundation\JsonResponse
+ *   A JSON response object without the actual content.
  */
 function _toolbar_initialize_page_cache() {
   $GLOBALS['conf']['system.performance']['cache']['page']['enabled'] = TRUE;
@@ -134,15 +138,17 @@ function _toolbar_initialize_page_cache() {
   }
 
   // Otherwise, create a new page response (that will be cached).
-  drupal_add_http_header('X-Drupal-Cache', 'MISS');
+  $json_response = new JsonResponse();
+  $json_response->headers->set('X-Drupal-Cache', 'MISS');
 
   // The Expires HTTP header is the heart of the client-side HTTP caching. The
   // additional server-side page cache only takes effect when the client
   // accesses the callback URL again (e.g., after clearing the browser cache or
   // when force-reloading a Drupal page).
   $max_age = 3600 * 24 * 365;
-  drupal_add_http_header('Expires', gmdate(DATE_RFC1123, REQUEST_TIME + $max_age));
-  drupal_add_http_header('Cache-Control', 'private, max-age=' . $max_age);
+  $json_response->headers->set('Expires', gmdate(DATE_RFC1123, REQUEST_TIME + $max_age));
+  $json_response->headers->set('Cache-Control', 'private, max-age=' . $max_age);
+  return $json_response;
 }
 
 /**
diff --git a/core/update.php b/core/update.php
index c94b4c5..a64cb94 100644
--- a/core/update.php
+++ b/core/update.php
@@ -228,8 +228,6 @@ function update_info_page() {
  *   Rendered HTML warning with 403 status.
  */
 function update_access_denied_page() {
-  drupal_add_http_header('Status', '403 Forbidden');
-  header(\Drupal::request()->server->get('SERVER_PROTOCOL') . ' 403 Forbidden');
   watchdog('access denied', 'update.php', NULL, WATCHDOG_WARNING);
   $output = '<p>Access denied. You are not authorized to access this page. Log in using either an account with the <em>administer software updates</em> permission or the site maintenance account (the account you created during installation). If you cannot log in, you will have to edit <code>settings.php</code> to bypass this access check. To do this:</p>
 <ol>
@@ -391,6 +389,7 @@ function update_task_list($active = NULL) {
 ini_set('display_errors', TRUE);
 
 
+$response = new Response();
 // Only proceed with updates if the user is allowed to run them.
 if (update_access_allowed()) {
 
@@ -447,6 +446,7 @@ function update_task_list($active = NULL) {
 }
 else {
   $output = update_access_denied_page();
+  $response->setStatusCode(403);
 }
 if (isset($output) && $output) {
   // Explicitly start a session so that the update.php token will be accepted.
@@ -457,7 +457,6 @@ function update_task_list($active = NULL) {
     $output->send();
   }
   else {
-    drupal_add_http_header('Content-Type', 'text/html; charset=utf-8');
     $maintenance_page = array(
       '#theme' => 'maintenance_page',
       // $output has to be rendered here, because the maintenance page template
@@ -470,6 +469,8 @@ function update_task_list($active = NULL) {
     if (isset($output['#title'])) {
       $maintenance_page['#page']['#title'] = $output['#title'];
     }
-    print drupal_render($maintenance_page);
+    $response->setContent(drupal_render($maintenance_page));
+    $response->headers->set('Content-Type', 'text/html; charset=utf-8');
+    $response->send();
   }
 }
