Razor Page에서 Ajax로 Post 요청하기

Doosan published on
2 min, 304 words

Categories: post

Tags: C#

오늘도 평화롭게 코딩하고 있는데 내 시간을 2시간 넘게 잡아먹는 일이 생겨서 어떤 일이 생겼는지 간단 하게 적어본다.

Razor page에서 ajax를 사용하여 사진을 업로드 하는 작업을 하고 있었다. 항상 OnGet, OnPost 같이 간단한 함수만 사용하다가 form 제출 없이 사진 업로드를 하려고 하다보니 ajax외에는 방법이 없는거 같았다. 그래서 서버에 간단한 요청을 날리는 것을 해보려고 했는데 생각대로 되지 않았다.

Named handler method

사진업로드하는 handler이름이 UploadPicture였는데 404 not found 에러가 났다.
구글링을 좀 해보니 razor page에는 named handler methods라는 기능이 있었다. Handler를 만들때 post request를 보내고 싶으면 OnPost, get request를 보내고 싶으면 OnGet으로 핸들러 이름을 시작하고, 그 뒤에 원하는 이름을 적으면 된다.
예를 들어 나의 핸들러는 Post request이고 UploadPicture라는 이름의 함수였으니까 OnPostUploadPicture라고 이름하면 된다.

Anti Forgery Token

이상하게도 핸들러 이름이 분명 정확한데 여전히 요청이 실패했다. 그래서 이름을 OnGetUploadPicture로 바꾸어 봤는데 GET 요청은 잘 되었다. 또 구글링을 했고 여기서 답을 찾았다. Razor Pages는 unsafe HTTP method(POST 같은 요청)에 대해 antiforgery validation을 자동으로 적용하므로 AJAX POST에도 request verification token을 같이 보내야 한다. 일반적으로 토큰이 없거나 잘못되면 handler까지 도달하지 못하고 400 Bad Request가 난다.
나는 그냥 input element 아래에

@Html.AntiForgeryToken() 

추가해주었다. 그리고 ajax request에는 아래의 코드를 추가했다

beforeSend: function (xhr) {
    xhr.setRequestHeader("XSRF-TOKEN",
        $('input:hidden[name="__RequestVerificationToken"]').val());
},

Anti forgery token을 추가했는데도 404가 반환되어서 다시 구글링해보니, 내가

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
}

이부분을 빼먹어서 그랬다. header name을 바꾸고 싶다면 modern hosting model에서는 보통 Program.cs에서 아래처럼 설정한다.

builder.Services.AddAntiforgery(options =>
{
    options.HeaderName = "XSRF-TOKEN";
});

기본 form field 이름은 __RequestVerificationToken이고, header로 보낼 때는 app의 antiforgery 설정이 기대하는 header name과 맞아야 한다. 나는 Program.cs 설정 건드리기 귀찮아서 AJAX request의 header name을 RequestVerificationToken로 바꾸어 주었더니 잘 동작했다.

참고한 자료
https://www.talkingdotnet.com/handle-ajax-requests-in-asp-net-core-razor-pages/
https://www.mikesdotnetting.com/article/308/razor-pages-understanding-handler-methods
https://www.learnrazorpages.com/security/request-verification
https://learn.microsoft.com/en-us/aspnet/core/razor-pages/
https://learn.microsoft.com/en-us/aspnet/core/security/anti-request-forgery