Search code examples
javascriptasp.netfetch-apirazor-pages

Javascript Fetch using POST always returns status 400


Just following all the examples in ChatGTP and Google but my first use of javascript fetch with POST always returns 400. (I have a fetch using GET which works fine so I don't understand why POST fails.)

Here is the Fetch javascript code:

async function FetchPost() {
    let data = { a: 1, b: 2 };
    let json = JSON.stringify(data);
    try {
        const response = await fetch('/FetchDemo?handler=Fetch',
            {
                method: 'POST',
                // adding mode, cache and credentials did not help
                mode: 'cors', 
                cache: 'no-cache', 
                credentials: 'same-origin', 
                headers: { 'Content-Type': 'application/json' },
                body: json
            });

        if (response.ok) {
            data = await response.json();
        } else {
            throw new exception(response.statusText);
        }
    } catch (error) {
        data = 'Error fetching data:' + error;
    }
    return data;
}

Here is the OnGet (which works) and the OnPost method but it is never executed. The Network log in the browser shows the 400 status.

public class FetchDemoModel : PageModel {
    public void OnGet() {
    }
    // This always works
    public IActionResult OnGetFetch(string action, string identity) {
        string data = "";
        switch(action.ToLower()) {
            case "find":
                break;
            default:
                data = "action=" + action + ", identity=" + identity; 
                break;
        }
        return new JsonResult(data);
    }
    // This code is never executed
    public IActionResult OnPostFetch() {
        string data = "";
        return new JsonResult(data);
    }
}

For completeness and comparison here is the javascript fetch GET which works.

async function FetchGet(action, identity) {
    let data = null;
    try {
        let url = '/FetchDemo?handler=Fetch&action=' + action + "&identity=" + identity;
        const response = await fetch(url,
        {
            method: 'GET',
        });

        if (response.ok) {
            data = await response.json();
        } else {
            throw new exception(response.statusText);
        }
    } catch (error) {
        data = 'Error fetching data:' + error;
    }
    return data;
}

I have checked all the issues which ChatGPT says may cause a 400 error to no avail. Can you help diagnose this?


Solution

  • The POST request is missing the required request verification token:

    In short, you can either switch off request verification for the PageModel class by adding an IgnoreAntiforgeryToken attribute to it:

    [IgnoreAntiforgeryToken(Order = 10001)]
    public class FetchDemoModel : PageModel
    {
        ....
    

    Or you can generate a hidden field using the Html.AntiForgeryToken helper in the view file and include it in the request headers:

    var token = document.querySelector('input[name="__RequestVerificationToken"]').value;
    fetch(..., {
        method: "post",
        headers: {
            "RequestVerificationToken": token
        },
        body: { foo: "bar" }
    }).then(() => {
        ...
    });