[HTML] form에서 Enter key를 누르면 405 Method Not Allowed error가 발생하는 문제 해결하기

lsjbh45·2022년 10월 12일
0

오류의 원인

이 문제는 몇 년 전에 개발되어 서비스 중이던 웹 어플리케이션에 대한 유지보수 의뢰가 도착해 새로운 기능을 일부 추가해서 배포한 후에 발견하게 된 문제이다. 해당 체계는 jQuery와 ajax 기법을 기반으로 개발된 체계였기 때문에 최대한 코드 작성 스타일을 비슷하게 해서 개발했는데, 개발 및 테스트 과정에서 미처 인지하지 못했던 html element의 기능에 의해 오류가 발생한 것이었다.

<html>
    <!-- ... -->
    <form id="updateData" method="post">
        <input type="hidden" name="seq" value="${data_obj.seq}" />
        <input type="hidden" name="txt" value="${data_obj.txt}" />
        <input type="text" name="date_fm" value="${data_obj.date_fm}" />
    </form>
    <button id="updateDataButton" />
    <!-- ... -->
    <script>
        /* ... */
        $(document).ready(function(e) {
            $("#updateDataButton").click(function(e) {
                $.ajax("/pvData/updateData.ajax", {
                    "seq": $("input[name=seq]").val(),
                    "txt": $("input[name=txt]").val(),
                    "date_fm": $("input[name=date_fm]").val()
                }, function(response) {
                    if(JSON.parse(response) == "success") {
                        opener.window.location.reload(-1);
                        window.close();
                    }
                })
            })
        }
        /* ... */
    </script>
</html>

위 코드는 오류가 발생한 팝업 페이지를 렌더링하기 위한 jsp 파일을 나타낸 것이다. 실제 코드는 bootstrap의 css를 적용하기 위한 class 속성, label tag 등이 포함되어 있어 복잡하기 때문에 작동 로직에 해당되는 코드 일부분만을 추려서 정리한 것이 위 코드이다. form tag가 자체적으로 제공하는 submission 기능을 이용하지 않고, jQuery의 ajax 구현체를 사용해 비동기적인 방식으로 서버에 업데이트 요청을 보낸 뒤 요청 성공 시 팝업 창을 닫고 이전 페이지로 돌아가도록 의도되어 있다.

의도한 바와 같이, 요청 버튼은 form tag 외부에 위치해 있기 때문에 버튼을 눌렀을 때는 form의 submission이 발생하지 않고 script에 명시된 바와 같이 작동한다. 하지만 input type="text" element 내부에서 enter key를 누르면 의도치 않게 form tag의 submission이 발생하면서 에러 페이지가 나타나게 된다. 이는 form tag 내에 input type="text" tag가 단 하나만 존재하는 경우에는 해당 element에 focusing이 된 상태로 enter key를 누르면 submission이 발생하도록 설계되어 있기 때문이다. 이 기능의 정확한 유래는 알 수 없지만 수십 년 전부터 브라우저 정책으로 지원되는 기능이었던 것으로 확인된다고 한다.

form tag 내부에 action 속성이 생략된 경우에는 해당 페이지를 호출한 서블릿으로 http 요청을 보내게 된다. 이때 method 속성으로 form tag의 http method는 POST로 지정해 주었기 때문에 요청이 POST로 보내지는데, 해당 url에 대해서 GET method에 대한 응답만이 구현되어 있고 POST method에 대한 응답이 구현되어 있지 않은 상태였기 때문에 405 Method Not Allowed 오류가 발생하게 된 것이다.

해결 방안

form submission 기능을 사용하지 않을 때는 form tag 사용하지 않기

form을 submit해서 서버로부터 받아온 마크업 데이터 전체를 렌더링하는 과거의 요청 방식과 달리, javascript를 이용해 비동기적으로 데이터를 처리하는 경우에는 form tag 자체를 사용할 필요가 없다. 사실 jQuery를 사용하거나 vanila javascript로 element selection을 해서 데이터를 가져오는 과정에서도 보통 class나 id 값으로 selection을 하는 경우가 대부분이기 때문이다. 내가 알지 못하는 또 다른 이유가 있을 수도 있겠지만, form tag의 사용이 개발 단계에서 어느 정도는 관성적으로 이루어지고 있었던 것 같다는 생각이 들었다. 이미 오류가 존재하는 채로 deploy가 된 상황이라 급하게 hotfix를 진행해야 했기 때문에 우선 간단하게만 조치해 두고, 나중에 코드 전체에 대한 리팩토링을 진행하는 것으로 합의하게 되었다.

간단한 해결책들

  • 보이지 않는 input type="text" tag를 하나 더 추가한다. input type="text" tag가 두 개 이상이기 때문에 focusing된 상태에서 enter key를 누르더라도 submission은 발생하지 않는다.
  • form tag에 onsubmit="return false;"를 추가한다. form tag에는 onsubmit 이벤트 핸들러가 있어서 submit event 이전의 전처리를 수행한다. 이때 전처리 함수의 결과가 false라면 submission을 진행하지 않는다.
  • keydown event 발생 시에 event.preventDefault()를 추가해서 event 발생을 취소한다.

여기에서는 세 번째 방식을 사용해서 간단히 문제를 해결하기로 했다.

<html>
    <!-- ... -->
    <script>
        /* ... */
        $(document).ready(function(e) {
            $("input").keydown(function(event) {
                if(event.keyCode === 13) {
                    event.preventDefault();
                }
            }
            /* ... */
        }
        /* ... */
    </script>
</html>

느낀 점

form tag를 이용한 submission은 사실 현 시점에서 개발되는 웹 어플리케이션들에서 많이 사용되지는 않는 기술이겠지만, 그럼에도 불구하고 현재 사용되는 모든 프레임워크들의 기반이 되는 기본적인 html element이기 때문에 언제 마주치게 될지 모르는 부분이다. 의도하지 않은 오류가 이처럼 사소한 곳에서도 발생할 수 있다는 것을 느끼게 만든 troubleshooting 과정이었던 것 같고, html element와 같은 기본적인 부분들도 확실히 검토하고, deploy 이전에 테스트를 확실하게 해야 한다는 점을 이해하게 되었다.

profile
개발을 공부하며 깊게 고민했던 트러블슈팅 과정을 공유하고자 합니다.

0개의 댓글