Next.js 서버 액션 unexpected response 오류: proxy의 로그인 리다이렉트
관리 화면에서 로그아웃을 눌렀는데 화면 전체가 「This page couldn't load」로 바뀌었습니다. 로그아웃 단추 하나가 페이지를 통째로 꺼 버린 셈입니다. 원인을 찾는 동안 한 번 틀렸고, 틀린 쪽으로 해결책까지 준비했습니다. 그 과정을 순서대로 적습니다.
관리 화면에서 로그아웃을 눌렀는데 화면 전체가 「This page couldn't load」로 바뀌었습니다. 로그아웃 단추 하나가 페이지를 통째로 꺼 버린 셈입니다. 원인을 찾는 동안 한 번 틀렸고, 틀린 쪽으로 해결책까지 준비했습니다. 그 과정을 순서대로 적습니다.
관리 화면 왼쪽 위에 사이드바를 접고 펴는 ☰ 버튼이 있습니다. 폭 하나 바꾸는 버튼인데, 대시보드에서 누르면 2초 넘게 아무 반응이 없었습니다. 레이아웃만 바꾸는 일이 왜 이렇게 오래 걸리는지부터 들여다봤습니다. Next.js 16 App Router 로 만든 제조 공장의 생산 관리 앱입니다.
제조 공장 한 곳의 생산 관리 앱을 만들고 있습니다. 그 안에 수주대장이라는 화면이 있는데, 공장이 쓰던 생산 엑셀을 칸 순서까지 그대로 옮긴 표입니다. 1년치만 봐도 4천 줄이 넘습니다. 처음에는 100줄씩 쪽으로 나눠 두었습니다. 직접 써 보다가 이 부분은 확실히 엑셀보다 불편하다는 생각이 들었습니다. 엑셀은 수천 …
테마 메뉴에서 디자인 시스템을 바꾸는 기능을 배포했습니다. 메뉴에는 「Betelgeuse 라임 다크」라고 정확히 찍히는데, 화면은 기본 시스템 그대로였습니다. 바로 전 배포에서는 같은 기능이 잘 동작했습니다. 그 사이에 바뀐 것은 디자인 시스템 패키지의 버전 하나였습니다.
형제 앱 하나의 운영 사이트맵을 열었더니 비어 있었습니다. <urlset> 태그만 있고 주소가 하나도 없었습니다. 코드에는 공개 경로 목록을 읽어 사이트맵을 만드는 sitemap.ts가 있었습니다. 목록도 비어 있지 않았습니다.
제조 공정을 관리하는 화면을 만들고 있습니다. 공정 카드마다 「피복 끝 → 가황」 같은 버튼이 있고, 누르면 다음 단계로 넘어갑니다. 써 보다가 걸리는 게 있었습니다. 전에 만든 다른 관리 화면은 누르는 순간 버튼이 바뀌는데, 이 화면은 통신이 끝나야 버튼이 돌아왔습니다.
사진 목록에서 사진을 누르면 모달로 크게 보여 주고, 같은 주소를 새 탭에서 열면 전체 페이지로 보여 주는 화면이 있습니다. 주소는 /photo/123 하나인데 보이는 모양이 둘입니다.
서버 컴포넌트에서 데이터를 읽는 코드는 이렇게 생깁니다.
공개하지 않고 내부에서만 여는 제품 카탈로그 데모에 언어 전환을 붙였습니다. 한국어, 영어, 중국어, 일본어, 독일어, 프랑스어 여섯 개입니다. 고른 언어는 쿠키에 저장하고, 쿠키가 없으면 브라우저의 Accept-Language 헤더를 봅니다. 주소는 나누지 않았습니다. /products/<기종> 하나로 여섯 언어를 모…
앱 라우터에서 서버로 무언가를 보내는 방법이 둘입니다. app/api/.../route.ts 에 라우트 핸들러를 만들거나, "use server" 를 붙인 서버 함수를 부르는 것입니다. 폼 하나를 붙일 때마다 어느 쪽을 쓸지 정해야 하는데, 「둘 다 서버에서 도니 아무거나」로 두면 나중에 갈립니다.
제품 카탈로그 데모를 만들면서 이미지 처리 방식을 정해야 했습니다. 화면에 나가는 사진은 제품 사진 몇 장과 로고뿐이고, 모두 저장소에 들어 있는 파일입니다. 요청마다 달라질 것이 없습니다.
같은 Docker 이미지를 스테이징과 운영에 함께 올리는 구성이 있습니다. 환경 변수는 각 환경의 설정으로 주입합니다. 서버 쪽 값은 환경에 맞게 잘 바뀌는데, 브라우저에서 쓰는 분석 도구 ID 만 두 환경에서 같은 값이 나옵니다. 스테이징의 방문 기록이 운영 통계에 섞입니다.
글을 발행하면 블로그의 RSS 에는 몇 초 만에 새 글이 들어오는데, 사이트맵에는 며칠째 들어오지 않았습니다. 응답 헤더의 age 값만 계속 올라갔습니다. 발행할 때 캐시 태그를 무효화하고 있었고, 그 태그는 글 목록과 RSS 가 함께 쓰는 태그였습니다. RSS 는 갱신되는데 사이트맵만 멈춰 있었습니다.
Next.js 앱 라우터에는 오류를 다루는 파일이 셋 있습니다. error.tsx, global-error.tsx, not-found.tsx 입니다. 이름만 보면 「오류 화면, 전체 오류 화면, 404 화면」으로 나뉘는 것 같은데, 실제로는 각자 감싸는 범위와 잡는 대상이 다릅니다. 하나로 다 될 것 같아서 error.…
Next.js 16 으로 올리면 middleware.ts 에 경고가 붙습니다. 파일 규칙 이름이 proxy 로 바뀌었다는 안내입니다. Proxy 문서의 첫 문장은 기능이 그대로라고 적습니다.
로딩 화면 파일 하나의 위치를 옮겨 push 했는데 Vercel 빌드가 실패했습니다. 페이지의 동작을 바꾸는 코드는 건드리지 않은 커밋이었습니다. 빌드 로그의 오류 줄은 이랬습니다.
Next.js 앱 라우터에서 한 폴더에는 이런 파일들이 함께 놓입니다.
한 번에 글을 일곱 편 발행한 날, 블로그 왼쪽의 카테고리 메뉴가 이상하게 보였습니다. 카테고리를 오가며 스크린샷 두 장을 찍었습니다. 첫 장은 전체 글 수가 377, 「데이터베이스 설계」가 14편이었고, 몇 초 뒤에 다른 카테고리를 눌러 찍은 둘째 장은 전체 370, 「데이터베이스 설계」 7편이었습니다. 메뉴가 글 수…
글을 두 편 발행하고 사이트맵을 열어 봤습니다. 둘 다 없었습니다.
Vercel 로 옮기고 나서 응답 헤더를 다시 봤더니 보안 헤더가 하나도 없었습니다. 예전에는 오리진 앞의 nginx 가 붙여 주고 있었는데, 그 nginx 가 경로에서 빠지면서 전 경로에서 같이 사라진 것입니다. 앱은 그대로였고 오류도 없었습니다. 헤더는 없어져도 화면이 멀쩡해서, 재보기 전에는 모릅니다.