 .../Core/Routing/RequestFormatRouteFilter.php      | 30 ++++++++++++++-
 .../Core/Routing/RequestFormatRouteFilterTest.php  | 44 ++++++++++++++++++----
 2 files changed, 66 insertions(+), 8 deletions(-)

diff --git a/core/lib/Drupal/Core/Routing/RequestFormatRouteFilter.php b/core/lib/Drupal/Core/Routing/RequestFormatRouteFilter.php
index 8119efa..547e611 100644
--- a/core/lib/Drupal/Core/Routing/RequestFormatRouteFilter.php
+++ b/core/lib/Drupal/Core/Routing/RequestFormatRouteFilter.php
@@ -23,7 +23,10 @@ public function applies(Route $route) {
    * {@inheritdoc}
    */
   public function filter(RouteCollection $collection, Request $request) {
-    $format = $request->getRequestFormat('html');
+    // Determine the request format.
+    $default_format = static::getDefaultFormat($collection);
+    $format = $request->getRequestFormat($default_format);
+
     /** @var \Symfony\Component\Routing\Route $route */
     foreach ($collection as $name => $route) {
       // If the route has no _format specification, we move it to the end. If it
@@ -48,4 +51,29 @@ public function filter(RouteCollection $collection, Request $request) {
     throw new NotAcceptableHttpException("No route found for the specified format $format.");
   }
 
+  /**
+   * Determines the default request format.
+   *
+   * By default, use 'html' as the default format. But when there's only a
+   * single route match, and that route specifies a '_format' requirement
+   * listing a single format, then use that as the default format.
+   *
+   * @param \Symfony\Component\Routing\RouteCollection $collection
+   *   The route collection to filter.
+   *
+   * @return string
+   *   The default format.
+   */
+  protected static function getDefaultFormat(RouteCollection $collection) {
+    $default_format = 'html';
+    if ($collection->count() === 1) {
+      $only_route = $collection->getIterator()->current();
+      $required_format = $only_route->getRequirement('_format');
+      if (strpos($required_format, '|') === FALSE) {
+        $default_format = $required_format;
+      }
+    }
+    return $default_format;
+  }
+
 }
diff --git a/core/tests/Drupal/Tests/Core/Routing/RequestFormatRouteFilterTest.php b/core/tests/Drupal/Tests/Core/Routing/RequestFormatRouteFilterTest.php
index 39a960b..c6d2843 100644
--- a/core/tests/Drupal/Tests/Core/Routing/RequestFormatRouteFilterTest.php
+++ b/core/tests/Drupal/Tests/Core/Routing/RequestFormatRouteFilterTest.php
@@ -5,6 +5,7 @@
 use Drupal\Core\Routing\RequestFormatRouteFilter;
 use Drupal\Tests\UnitTestCase;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\Exception\NotAcceptableHttpException;
 use Symfony\Component\Routing\Route;
 use Symfony\Component\Routing\RouteCollection;
 
@@ -35,10 +36,20 @@ public function testAppliesWithFormat() {
 
   /**
    * @covers ::filter
+   * @dataProvider filterProvider
    */
-  public function testFilter() {
+  public function testFilter(RouteCollection $collection, $request_format, array $expected_filtered_collection) {
     $route_filter = new RequestFormatRouteFilter();
 
+    $request = new Request();
+    $request->setRequestFormat($request_format);
+    $collection = $route_filter->filter($collection, $request);
+
+    $this->assertCount(count($expected_filtered_collection), $collection);
+    $this->assertSame($expected_filtered_collection, array_keys($collection->all()));
+  }
+
+  public function filterProvider() {
     $route_without_format = new Route('/test');
     $route_with_format = $route = new Route('/test');
     $route_with_format->setRequirement('_format', 'json');
@@ -50,13 +61,16 @@ public function testFilter() {
     $collection->add('test_1', $route_with_format);
     $collection->add('test_2', $route_with_multiple_formats);
 
-    $request = new Request();
-    $request->setRequestFormat('xml');
-    $collection = $route_filter->filter($collection, $request);
+    $sole_route_match_single_format = new RouteCollection();
+    $sole_route_match_single_format->add('sole_route_single_format', $route_with_format);
 
-    $this->assertCount(2, $collection);
-    $this->assertEquals(array_keys($collection->all())[0], 'test_2');
-    $this->assertEquals(array_keys($collection->all())[1], 'test_0');
+    return [
+      'xml requested' => [clone $collection, 'xml', ['test_2', 'test_0']],
+      'json requested' => [clone $collection, 'json', ['test_1', 'test_2', 'test_0']],
+      'html format requested' => [clone $collection, 'html', ['test_0']],
+      'no format requested, defaults to html' => [clone $collection, NULL, ['test_0']],
+      'no format requested, single route match with single format, defaults to that format' => [clone $sole_route_match_single_format, NULL, ['sole_route_single_format']],
+    ];
   }
 
   /**
@@ -77,4 +91,20 @@ public function testNoRouteFound() {
     $route_filter->filter($collection, $request);
   }
 
+  /**
+   * @covers ::filter
+   */
+  public function testNoRouteFoundWhenNoRequestFormatAndSingleRouteWithMultipleFormats() {
+    $this->setExpectedException(NotAcceptableHttpException::class, 'No route found for the specified format html.');
+
+    $collection = new RouteCollection();
+    $route_with_format = $route = new Route('/test');
+    $route_with_format->setRequirement('_format', 'json|xml');
+    $collection->add('sole_route_multiple_formats', $route_with_format);
+
+    $request = Request::create('test', 'GET');
+    $route_filter = new RequestFormatRouteFilter();
+    $route_filter->filter($collection, $request);
+  }
+
 }
