Skip to content

[Bug]: Empty Response with Content-Type: application/json Throws Error #11145

Closed
@SpencerDuball

Description

@SpencerDuball

What version of React Router are you using?

@remix-run+router@1.14.1

Steps to Reproduce

This is the _index.tsx page of a default Remix app. Clicking the button if running locally will trigger this issue. I have also included an example of the Link component because the issue appears to exist in the same place on different hosting provider such as AWS CloudFront. In AWS CloudFront it appears that empty requests are sent back as Content-Type: application/json which includes client-side navigation with Link components.

import { Link, useFetcher } from "@remix-run/react";
import { type ActionFunctionArgs } from "@remix-run/node";

export async function action({ request }: ActionFunctionArgs) {
  const body = await request.formData();

  if (request.method === "POST") {
    return new Response(null, { headers: [["Content-Type", "application/json"]] });
  }

  return new Response(null, { status: 405, statusText: "Method Not Allowed" });
}

export default function Index() {
  const action = useFetcher();

  return (
    <div>
      {/* Link Issue Parsing Empty Response
          ---------------------------------
          When using a Link component, if the response is an empty response from the server with
          Content-Type: application/json an error will be thrown that the json could not parse correctly.
          NOTE: The Link example will not reproduce locally because the Content-Type header will not be set to 
          application/json, but on other providers such as AWS CloudFront, empty responses have application/json set
          by default! */}
      <li>
        <Link to="/non-existing-route">Will Cause Error</Link>
      </li>
      {/* Fetcher Issue Parsing Empty Response
          ------------------------------------
          When using a fetcher, if an empty response is sent from the server with Content-Type: application/json
          an error will be thrown that the json could not parse correctly. */}
      <action.Form method="post">
        <button type="submit">Fetcher Issue</button>
      </action.Form>
    </div>
  );
}

Expected Behavior

Issue Location
The issue comes from this line in the @remix-run/router package:

data = await result.json();

Proposed Solution
In this section, we are checking if the Content-Type: application/json exists, and then parsing for a JSON response. However, if the response body is null an error will be thrown. I believe adding a check for Content-Length: 0 before attempting to parse for JSON would be good.

Reason For Solution
I have looked in RFC#7231 and RFC#2616 and the way this package is parsing for the Content-Type: application/json certainly is correct - however a bit of a blindspot in the RFCs is how to deal appropriately with Empty responses:

  • Some guidance is to not have a Body and not include a Content-Type header
  • Some guidance is to check for the Content-Length: 0 header value.
  • Some guidance is to only use the Content-Type value.

The RFCs also indicate that the Content-Type is an optional field. It SHOULD be sent but is not required as the client may attempt to parse the payload format on it's own. In this issue I have highlighted where I am recieving an issue from AWS CloudFront which seems to be relying on checking the Content-Length: 0 header.

For these reasons, I think it would be a good improvement to check the Content-Length: 0 even though the current implementation is valid.

Actual Behavior

Currently there is no check for an empty body before attempting to parse for JSON. Right now if the Content-Type: application/json header is sent then React Router/Remix will parse for JSON.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions