间歇性 405 方法不允许用于 Next.js/Vercel 和服务器操作

问题描述 投票:0回答:1

我们尝试在 Vercel 中部署的 Next.js

14.2.13
中实现服务器操作,但每 4/5 次调用我们都会收到间歇性的 405 状态代码

这是函数

'use server';

import {
  CreateNoteFormDataSchema,
  NoteFormInputs,
} from '@/src/features/Notes/CreateNoteInDeck/NoteForm/createNoteSchema';
import axios from 'axios';
import { BASE_URL } from '@/src/app/api/Api';
import { getServerSession } from 'next-auth';
import { authOptions } from '@/src/app/api/auth/[...nextauth]/authOptions';
import { getHeaders } from '@/src/app/api/getHeaders';
import { sanitizeHTML } from '@/src/app/api/utils/sanitizeHTML';
import { FontTypes } from '@/src/features/Notes/utils/FontFamilyConfig';

type CreateNoteReqBody = {
  title: string;
  body: string;
  deckId?: number | null;
  tags: string[];
  pattern: string | null;
  backgroundColor: string | null;
  fontFamily: string | null;
  visibility: 'public' | 'private' | 'friends';
};

type CreateNoteResBody = {
  noteId: string;
  deckId: number | null;
  title: string;
  body: string;
  bodySummary: string;
  tags: string[];
  pattern: string | null;
  backgroundColor: string | null;
  fontFamily: string | null;
  visibility: 'public' | 'private' | 'friends';
  updatedAt: string;
};

export type CreateNoteServerActionState = {
  success: boolean;
  error: string | null;
  data: CreateNoteResBody | null;
};

export async function _createNoteServerAction(data: NoteFormInputs): Promise<CreateNoteServerActionState> {
  try {
    const parsedData = CreateNoteFormDataSchema.parse({
      deckId: data.deckId,
      backgroundColor: data.backgroundColor,
      fontType: data.fontType,
      visibility: data.visibility,
      title: sanitizeHTML(data.title),
      body: sanitizeHTML(data.body),
      tags: data.tags?.map((tag) => sanitizeHTML(tag)) || [],
    });

    const validatedData: CreateNoteReqBody = {
      deckId: parsedData.deckId || null,
      title: parsedData.title,
      body: parsedData.body,
      backgroundColor: parsedData.backgroundColor || null,
      visibility: parsedData.visibility,
      fontFamily: data.fontType || FontTypes[0],
      pattern: null,
      tags: parsedData.tags || [],
    };

    const session = await getServerSession(authOptions);
    const config = getHeaders(session?.accessToken);

    const response = await axios.post<CreateNoteResBody>(`${EXTERNAL_API_BASE_URL}/note`, validatedData, config);

    return { success: true, data: response.data, error: null };
  } catch (error) {
    console.error('createNoteServerAction', error);
    return { success: false, error: 'Something went wrong', data: null };
  }
}

从这里调用:


 const {
    register,
    handleSubmit,
    control,
    formState: { errors },
    watch,
    setValue,
  } = useForm<NoteFormInputs>({
    defaultValues: {
      deckId,
      title: defaultNote?.title || '',
      body: defaultNote?.body || '',
      backgroundColor: defaultNote?.backgroundColor || '',
      pattern: defaultNote?.pattern || '',
      fontType: defaultNote?.font.name || FontTypes[0],
      visibility: defaultNote?.visibility || 'public',
      tags: defaultNote?.tags || [],
    },
    resolver: zodResolver(CreateNoteFormDataSchema),
  });

// ....

const onSubmit: SubmitHandler<NoteFormInputs> = useCallback(
    (data) => {
      startTransition(async () => {
        if (defaultNote?.id) {
          const editResult = await _editNoteServerAction(defaultNote.id, data);

          if (editResult.success && editResult.data) {
            BBToast.success('Note updated');
            return;
          }
          BBToast.error('Failed to update note');
          return;
        }

        const result = await _createNoteServerAction(data);

        if (result.success && result.data) {
          BBToast.success('Note created');
          return router.replace(`${pathName}/../${result.data.noteId}`);
        }
        BBToast.error('Failed to create note');
        return;
      });
    },
    [defaultNote?.id, pathName, router],
  );

// ....
    <form onSubmit={handleSubmit(onSubmit)} className="p-4 h-full">

Vercel 的原木是

500
enter image description here

在客户端 chrome 控制台上有一个

405
enter image description here

任何有关为什么会发生这种情况的帮助、想法或解释,我们将不胜感激!

next.js vercel server-action
1个回答
0
投票

就我而言,这是由于标题中设置了错误的

Content-Security-Policy

就我而言,它位于

vercel.json
文件中。

这是我更新的配置:

{
  "key": "Content-Security-Policy",
  "value": "default-src 'self'; script-src 'self' THIRD_PARTY_API_URL_1 THIRD_PARTY_API_URL_2; style-src 'self' 'unsafe-inline'; img-src IMAGE_PROVIDER_URL 'self' data:; connect-src 'self' BACKEND_URL THIRD_PARTY_API_URL; frame-src 'self' EXTERNAL_I_FRAME_URL"
}

您在哪里更新

...API_URL...
并使用 url(接受通配符)

您可以在此处生成内容安全策略

© www.soinside.com 2019 - 2024. All rights reserved.