Form ID

Nuxt

하이드레이션 전에는 일반 폼으로, 이후에는 $fetch로 POST하는 Nuxt 컴포넌트. 폼 ID는 런타임 설정에 둡니다. nuxt generate와 함께 작동합니다.

Nuxt는 서버에서 폼을 렌더링하므로, 브라우저에 도착한 HTML은 이미 작동하는 폼입니다. 앱이 하이드레이션되기 전에는 일반 HTML 폼처럼 POST하고, 그 이후에는 컴포넌트가 이어받아 결과를 그 자리에 보여 줍니다. 서버에서 실행되는 것이 없으므로 nuxt generate로 빌드한 정적 사이트에서도 작동합니다.

대신 시크릿 키를 사용해 Nuxt 서버 라우트에서 POST하려면 Vue를 참고하세요.

설정하기

  1. 폼 ID를 런타임 설정에 넣기

    nuxt.config.ts
    export default defineNuxtConfig({
      runtimeConfig: {
        public: {
          ikiformFormId: "frm_xxxxxxxxxxxxxxxx",
        },
      },
    });

    환경마다 NUXT_PUBLIC_IKIFORM_FORM_ID로 덮어쓸 수 있습니다. nuxt generate를 쓰면 값이 빌드 시점에 고정되므로 빌드 환경에 변수를 설정하세요.

  2. 컴포넌트 추가하기

    app/components/ContactForm.vue
    <script setup lang="ts">
    type Result =
      | { ok: true; id: string }
      | { ok: false; error: { message: string; fields?: Record<string, string[]> } };
    
    const config = useRuntimeConfig();
    const endpoint = `https://ikiform.com/f/${config.public.ikiformFormId}`;
    
    const status = ref<"idle" | "sending" | "sent" | "error">("idle");
    const errors = ref<Record<string, string[]>>({});
    const message = ref("");
    
    async function onSubmit(event: Event) {
      status.value = "sending";
      const result = await $fetch<Result>(endpoint, {
        method: "POST",
        headers: { Accept: "application/json" },
        body: new FormData(event.currentTarget as HTMLFormElement),
        ignoreResponseError: true,
      }).catch(() => null);
      if (result?.ok) {
        status.value = "sent";
        return;
      }
      errors.value = result?.error.fields ?? {};
      message.value = result?.error.message ?? "Couldn't reach the server. Try again.";
      status.value = "error";
    }
    </script>
    
    <template>
      <p v-if="status === 'sent'">Thanks, we got it.</p>
      <form v-else :action="endpoint" method="post" @submit.prevent="onSubmit">
        <label>
          Email
          <input name="email" type="email" autocomplete="email" required />
        </label>
        <p v-if="errors.email">{{ errors.email[0] }}</p>
        <label>
          Message
          <textarea name="message" rows="5" />
        </label>
        <input type="hidden" name="_redirect" value="https://example.com/thanks" />
        <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
        <p v-if="status === 'error' && !errors.email" role="alert">{{ message }}</p>
        <button :disabled="status === 'sending'">{{ status === "sending" ? "Sending" : "Send" }}</button>
      </form>
    </template>
    • Nuxt 3에서는 app/components/ 대신 components/에 넣으세요.
    • ignoreResponseError: true를 쓰면 $fetch가 4xx에서 예외를 던지지 않으므로 오류 형식이 데이터로 돌아옵니다. 네트워크 오류만 catch에 도달합니다.
    • @submit.prevent는 앱이 하이드레이션된 뒤에만 존재합니다. 그 전에는 브라우저가 action으로 POST하고 _redirect를 따릅니다.
  3. 페이지에서 사용하기

    app/pages/contact.vue
    <template>
      <ContactForm />
    </template>

대체 동작에는 서버 렌더링이나 프리렌더링이 필요합니다. ssr: false이면 JavaScript가 실행될 때까지 페이지가 비어 있어서, JavaScript 없이 POST할 폼이 없습니다.

허용 도메인

프로덕션과 배포처의 미리보기 호스트를 등록하세요.

폼이 실행되는 곳Allowed domains에 추가할 값
nuxt devlocalhost. http://localhost:3000과 일치합니다. Ikiform은 포트가 아니라 호스트 이름만 비교합니다.
여러분의 도메인example.com, www.example.com도 포함
Vercelyour-project.vercel.app. your-project-git-branch-team.vercel.app 같은 미리보기 URL은 일치하지 않으므로, 테스트하는 동안 정확한 미리보기 호스트를 추가하세요.
Netlifyyour-site.netlify.app. 배포 미리보기(deploy-preview-12--your-site.netlify.app)와 브랜치 배포(branch--your-site.netlify.app)는 하위 도메인이 아니므로, 테스트하는 동안 정확한 미리보기 호스트를 추가하세요.
Cloudflare Pagesyour-project.pages.dev. abc123.your-project.pages.dev 같은 미리보기 URL은 하위 도메인이므로 이미 일치합니다.
  • vercel.app, netlify.app, pages.dev만 단독으로 추가하지 마세요. 다른 사람의 사이트를 포함해 그 호스트의 모든 사이트가 일치하게 됩니다.

테스트 체크리스트

  1. 허용 도메인에 localhost를 넣고 nuxt dev를 실행해 제출하세요. 감사 메시지가 폼을 대체해야 합니다.
  2. 브라우저 개발자 도구에서 JavaScript를 끄고 새로 고친 뒤 제출하세요. 로컬에서는 Ikiform의 감사 페이지로, https: 도메인에서는 /thanks로 이동해야 합니다.
  3. 필드를 정의한 상태에서 잘못된 이메일을 제출하고 필드 아래에 메시지가 나타나는지 확인하세요.
  4. nuxt generate를 실행하고 결과물을 배포한 뒤 미리보기 호스트에서 제출하세요.

문제 해결

증상원인해결
FetchError: [POST] "https://ikiform.com/f/...": 422ignoreResponseError가 없어서 $fetch가 오류에서 예외를 던짐ignoreResponseError: true를 추가하세요.
404 not_found, action이 /f/undefined로 끝남사이트를 빌드할 때 폼 ID가 설정되지 않음빌드 환경에 NUXT_PUBLIC_IKIFORM_FORM_ID를 설정하거나 nuxt.config.ts에 기본값을 넣으세요.
JavaScript 없이는 아무 일도 일어나지 않음페이지가 ssr: false로 클라이언트에서 렌더링됨서버 렌더링을 켜거나 페이지를 프리렌더링하세요.
제출이 origin_mismatch와 함께 스팸 필터에 들어감POST한 페이지가 폼의 허용 도메인에 없음위 표의 호스트를 추가하세요. Reject를 골랐다면 같은 POST가 대신 403 origin_not_allowed를 받습니다.