노트

서버 함수와 서버 액션

Server Functions and Server Actions

프런트엔드#react#nextjs · 연결된 개념 12개

쉽게 말하면

서버 함수는 브라우저에서 평범한 함수처럼 부르지만 실제 요리는 서버 주방에서만 하는 함수예요. 손님은 주문서만 건네고 레시피는 못 보죠. API 라우트와 fetch를 손으로 잇던 일을 줄여 줘요.

비유가 깨지는 곳 주문 창구가 앱 화면 안에만 있는 게 아니에요. 서버 함수는 누구나 POST로 직접 부를 수 있는 엔드포인트라서, 함수마다 입력 검증과 인증·인가를 꼭 해야 해요.

서버 함수(Server Function)는 'use server'로 표시해 서버에서만 실행되지만 클라이언트에서 네트워크 요청으로 호출할 수 있는 async 함수다. 그중 폼 제출이나 데이터 변경처럼 action 맥락(form action, transition)에서 쓰이는 것을 서버 액션(Server Action)이라 부른다. 서버 액션은 서버 함수의 부분집합이다.

// actions.ts
'use server'
export async function createProduct(formData: FormData) {
  const session = await auth()                       // 인가 확인 필수
  if (!session) throw new Error('Unauthorized')
  const name = z.string().min(1).parse(formData.get('name')) // 입력 검증 필수
  await db.product.create({ data: { name } })
  revalidatePath('/products')                         // 관련 캐시 무효화
}
<form action={createProduct}><input name="name" /><button>저장</button></form>
  • 흔한 오해: 서버 컴포넌트에서 await getProducts()로 부르는 일반 데이터 조회 함수는 서버에서 실행될 뿐 서버 함수가 아니다. 'use server'가 없으면 클라이언트가 부를 수 있는 엔드포인트가 생기지 않는다
  • 동작: 함수 코드는 클라이언트로 가지 않고 참조만 넘어간다(페이로드의 $h). 호출하면 React가 인자를 직렬화해 POST로 보내고 결과를 돌려받는다(RPC). 인자와 반환값은 직렬화할 수 있는 값이어야 한다
  • 역할: 읽기는 서버 컴포넌트의 await나 use()로, 쓰기는 서버 액션으로 한다. 서버 액션은 렌더 중이 아니라 사용자 이벤트로 실행되므로 "렌더 중 부수 효과 금지" 규칙과 맞는다(부수 효과와 Effect)
  • API(Application Programming Interface) 라우트·fetch·로딩 상태를 손으로 배선하던 일을 줄여 준다. 대신 외부 클라이언트가 쓰는 공개 API에는 맞지 않는다
  • 폼 상태는 useActionState와 폼 액션와 함께 쓴다. 추가 인자는 숨은 input보다 action.bind(null, id)가 낫다. 숨은 input은 값이 HTML(HyperText Markup Language)에 그대로 드러난다

보안

서버 함수는 앱 UI를 거치지 않고도 POST로 직접 호출할 수 있다. 인자는 전부 클라이언트가 조작할 수 있는 신뢰할 수 없는 입력이다. 함수마다 입력을 검증하고 인증·인가를 확인한다. 예전 API 라우트에서 하던 검사를 그대로 해야 한다(CSRF(Cross-Site Request Forgery)).

출처: Next.js - Mutating Data

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • 서버 렌더에서 훅이 하는 일

    서버 렌더(Server-Side Rendering, SSR)에서도 컴포넌트 함수는 실제로 호출되고, 그 안의 훅도 호출은 된다. 다만 서버에는 커밋(DOM 반영)이 없어서, 렌더 중 동기적으로 값을 계산하는 훅만 일하고 커밋 뒤에 도는 훅은 아무것도 하지 않는다. "이 훅은 클라이언트에서만 동작한다"는 말은 대개 "Effect 안의 일은 클라이언트에서만 일어난다"는 뜻이다.

  • 서버 전송 이벤트(SSE)

    서버 전송 이벤트(Server-Sent Events, SSE)는 HTTP(HyperText Transfer Protocol) 응답 하나를 닫지 않고 열어 둔 채, 서버가 원할 때마다 텍스트 이벤트를 흘려보내는 서버 → 클라이언트 단방향 푸시 방식이다. HTML 표준에 정의돼 있고 브라우저는 EventSource로 받는다.

  • Spring MVC 요청 흐름

    Spring MVC는 모든 HTTP 요청을 DispatcherServlet 하나가 받아, 알맞은 컨트롤러 메서드로 보내고 결과를 응답으로 바꾸는 프런트 컨트롤러(Front Controller) 구조다. 스프링 이전에는 URL마다 서블릿을 직접 만들고 매핑했다.

  • XSS

    XSS(Cross-Site Scripting)는 공격자가 넣은 스크립트가 내 사이트의 출처(origin) 권한으로 사용자 브라우저에서 실행되는 공격이다. 같은 출처의 코드로 돌기 때문에 same-origin-policy가 막아 주지 못한다. 그 스크립트는 페이지를 바꾸고, 로그인한 사용자 행세를 하며 요청을 보내고, JS가 읽을 수 있는 데이터(localStorage의 토큰 등)를 빼 갈 수 있다.

보기 옵션