Search code examples
javascriptreactjsfetch-api

Fetch API Response Code Differs from Network Tab Response Code


I'm creating a React component which is intended to check for updates to a privacy policy page, based on whether the page is cached. I'm having two issues -

  1. The response code shown by the Response object differs from the response code shown in the network tab.
  2. Less critically, the request is being sent twice, and I'm not exactly sure why. This might be a problem with my logic or caused by something else in the application.

The Code

    //Set the state to undefined initial, it'll
    const [ppChanged, setPPStatus] = useState(undefined);
    function checkPrivacyPolicyChanged(url) {
        try {
            fetch(url)
            .then(
            response => {
                console.log("Response: ", response)
                if (response.ok && response.status !== 304) {
                    //If the response code is 200-299 (ok status), and isn't cached (as indicated by status 304)
                    //Tell the component that the privacy policy has had changes since the user last saw it
                    setPPStatus(true);
                } else if (response.status == 304) {
                    setPPStatus(false);
                } else {
                    console.log(response);
                }
            },
            //Error handling
            error => {throw Error(error)}
            )
        }
        catch(err) {
            console.log(err)
        }
    }
    //If we haven't determined the privacy policy state yet, check for it. (Using manifest.json for testing purposes)
    if (ppChanged == undefined) {

        checkPrivacyPolicyChanged("/manifest.json");
    }

    let color = "green";
    //If a change to the privacy policy is detected, give a visual cue
    if (ppChanged) {color = "purple"};
    return(
        <div style={{color}}>
            {props.children}
        </div>
    );
}

The Console (Note the response codes on the right) Console and Network Tab Output


Solution

  • 304 returned - 200 as fetch result

    The fetch standard describes this behaviour here.

    1. If response is null, then:

    See statusses for a description about null body status which are statusses that are 101, 204, 205, or 304.

    10.4 If the revalidatingFlag is set and forwardResponse’s status is 304, then:

    10.4.1 Update storedResponse’s header list using forwardResponse’s header list, as per the "Freshening Stored Responses upon Validation" chapter of HTTP Caching. [HTTP-CACHING]

    This updates the stored response in cache as well.

    10.4.2 Set response to storedResponse.

    What this means is that the 200 status code comes from the response your browser has previously stored and is serving because it received a 304. This makes sense, because the browser wouldn't be able to give you a response unless it queried the resource again (which is what is trying to be avoided with this 304 - Not modified status).

    Alternatives

    You could keep track of one of the following headers of the request instead and compare these to a previously stored value:

    Request being sent twice

    As mentionned in the comments, the solution to this is to use the useEffect-hook.

    useEffect(() => {
      ...
    }, []); // Note the empty dependency array ensures that this code will only be executed once during the lifetime of this component.
    

    The reason why this is needed is because during the rendering, this function will be executed more than once (for example, to update the state after a call to setPPStatus).

    When this function is re-executed, if the update hasn't occured yet, the if (ppChanged == undefined)-block would be executed multiple times and therefor trigger multiple API calls.

    By using the useEffect-hook with an empty dependency array, you ensure that this code will only be executed once.