Response.json 不是函数(仅当部署到 vercel 时,不在本地主机上)

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

我在注册/登录时创建了一个用户身份验证器,并且所有操作都在本地主机上完美运行,但我在 Vercel 部署中遇到了 TypeError。当我在注册/登录表单中输入无效数据并发出 POST 请求时,就会发生这种情况。

在我的

ActionFunction
中,您可以看到我
return Response.json({...})
的价值观。

我几乎遵循了 Remix 提供的教程,但他们使用了

json({..})
函数,该函数现已弃用。

非常感谢任何指导!谢谢,请在下面找到我的代码块。

应用程序/路线/login.tsx

import { useState, useRef, useEffect } from 'react'
import { useActionData } from '@remix-run/react'
import { Layout } from '~/components/layout'
import { FormField } from '~/components/form-field'
import { ActionFunction, LoaderFunction, redirect } from '@remix-run/node'
import { validateEmail, validateName, validatePassword } from '~/utils/validators.server'
import { login, register, getUser } from '~/utils/auth.server'

export const loader: LoaderFunction = async ({ request }) => {
    // If there's already a user in the session, redirect to the profile page
    return (await getUser(request)) ? redirect('/profile') : null
}

export const action: ActionFunction = async ({ request }) => {
    const form = await request.formData()
    const action = form.get('_action')
    const email = form.get('email')
    const password = form.get('password')
    let firstName = form.get('firstName')
    let lastName = form.get('lastName')

    if (typeof action !== 'string' || typeof email !== 'string' || typeof password !== 'string') {
        return Response.json({ error: `Invalid Form Data`, form: action }, { status: 400 })
    }

    if (action === 'register' && (typeof firstName !== 'string' || typeof lastName !== 'string')) {
        return Response.json({ error: `Invalid Form Data`, form: action }, { status: 400 })
    }

    const errors = {
        email: validateEmail(email),
        password: validatePassword(password),
        ...(action === 'register'
        ? {
            firstName: validateName((firstName as string) || ''),
            lastName: validateName((lastName as string) || ''),
            }
        : {}),
    }

    if (Object.values(errors).some(Boolean))
        return Response.json({ errors, fields: { email, password, firstName, lastName }, form: action }, { status: 400 })


    switch (action) {
        case 'login': {
            return await login({ email, password })
        }
        case 'register': {
            firstName = firstName as string
            lastName = lastName as string
            return await register({ email, password, firstName, lastName })
        }
        default:
            return Response.json({ error: `Invalid Form Data` }, { status: 400 });
      }
}


export default function Login() {
    const [formData, setFormData] = useState({
        email: '',
        password: '',
        firstName: '',
        lastName: '',
    })
    const [signActive, setSignActive] = useState(true);
    const actionData = useActionData<typeof action>()
    const firstLoad = useRef(true)
    const [errors, setErrors] = useState(actionData?.errors || {})
    const [formError, setFormError] = useState(actionData?.error || '')

    // Updates the form data when an input changes
    const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>, field: string) => {
        setFormData(form => ({ ...form, [field]: event.target.value }))
    }

    useEffect(() => {
        if (!firstLoad.current) {
          const newState = {
            email: '',
            password: '',
            firstName: '',
            lastName: '',
          }
          setErrors(newState)
          setFormError('')
          setFormData(newState)
        }
    }, [actionData])
    
    useEffect(() => {
        if (!firstLoad.current) {
            setFormError('')
        }
    }, [formData])
    
    useEffect(() => { errors ? firstLoad.current = true : firstLoad.current = false }, [actionData])

    useEffect(() => {
        // console.log('action data', actionData);
        // console.log('first load', firstLoad);
    }, [firstLoad])

  return (
    <Layout>
      <div className="h-full justify-center items-center flex flex-col gap-y-4">
        <h2 className="text-5xl font-extrabold text-yellow-300">Welcome to Kudos!</h2>
        {signActive ? <p className="font-semibold text-slate-300">Log In To Give Some Praise!</p> : <p className="font-semibold text-slate-300">Sign Up To Give Some Praise!</p>}

        <div className="border-red-700 flex justify-between text-black font-extrabold">
            <div className='shadow-red-500 shadow-sm border-red-500 border-2 rounded bg-red-500 hover:cursor-pointer p-1 m-1' onClick={() => setSignActive(!signActive)}>{!signActive ? 'Sign In' : 'Sign Up'}</div>
            {/* <div className='shadow-yellow-300 shadow-sm border-yellow-300 border-2 rounded bg-yellow-300 hover:cursor-pointer p-1 m-1 display' onClick={() => setSignActive(false)}>Sign Up</div> */}
        </div>
        {
            signActive ? 
            <form method="POST" className="rounded-2xl bg-gray-200 p-6 w-96">
                <div className="text-xs font-semibold text-center tracking-wide text-red-500 w-full">{formError}</div>
                <FormField
                    htmlFor="email"
                    label="Email"
                    value={formData.email}
                    onChange={e => handleInputChange(e, 'email')}
                    error={errors?.email}
                />
                <FormField
                    htmlFor="password"
                    type="password"
                    label="Password"
                    value={formData.password}
                    onChange={e => handleInputChange(e, 'password')}
                    error={errors?.password}
                />
                <button className="w-full text-center rounded-xl mt-2 bg-yellow-300 px-3 py-2 text-blue-600 font-semibold hover:bg-yellow-400 hover:cursor-pointer" name='_action' value='login'>Login</button>
            </form> : 
            <form method="POST" className="rounded-2xl bg-gray-200 p-6 w-96">
                <div className="text-xs font-semibold text-center tracking-wide text-red-500 w-full">{formError}</div>
                <FormField
                    htmlFor="email"
                    label="Email"
                    value={formData.email}
                    onChange={e => handleInputChange(e, 'email')}
                    error={errors?.email}
                />
                <FormField
                    htmlFor="password"
                    type="password"
                    label="Password"
                    value={formData.password}
                    onChange={e => handleInputChange(e, 'password')}
                    error={errors?.password}
                />
                <FormField
                    htmlFor="firstName"
                    label="First Name"
                    value={formData.firstName}
                    onChange={e => handleInputChange(e, 'firstName')}
                    error={errors?.firstName}
                />
                <FormField
                    htmlFor="lastName"
                    label="Last Name"
                    value={formData.lastName}
                    onChange={e => handleInputChange(e, 'lastName')}
                    error={errors?.lastName}
                />
                <button className="w-full text-center rounded-xl mt-2 bg-red-300 px-3 py-2 text-blue-600 font-semibold hover:bg-red-400 hover:cursor-pointer" name='_action' value='register'>Register</button>
            </form>
        }
        
      </div>
    </Layout>
  )
}

这是预期的输出以及它如何在本地主机上工作(这是用于表单验证,因此它应该返回 Response.json 错误消息(您可以在表单字段中看到,它在本地主机上工作)) working on localhost

这是 vercel 上显示的错误日志

TypeError: Response.json is not a function
at login (file:///var/task/xPortal/build/server/index.js:218:21)
at async action (file:///var/task/xPortal/build/server/index.js:498:14)
at async Object.callRouteAction (/var/task/xPortal/node_modules/@remix-run/server-runtime/dist/data.js:36:16)
at async /var/task/xPortal/node_modules/@remix-run/router/dist/router.cjs.js:4726:19
at async callLoaderOrAction (/var/task/xPortal/node_modules/@remix-run/router/dist/router.cjs.js:4792:16)
at async Promise.all (index 0)
at async defaultDataStrategy (/var/task/xPortal/node_modules/@remix-run/router/dist/router.cjs.js:4651:17)
at async callDataStrategyImpl (/var/task/xPortal/node_modules/@remix-run/router/dist/router.cjs.js:4683:17)
at async callDataStrategy (/var/task/xPortal/node_modules/@remix-run/router/dist/router.cjs.js:4093:19)
at async submit (/var/task/xPortal/node_modules/@remix-run/router/dist/router.cjs.js:3952:21)

[错误:意外的服务器错误]

json mongodb forms remix.run
1个回答
0
投票

解决了。我确保添加了 'v3_singlefetch 的 https://remix.run/docs/en/2.13.1/start/future-flags#v3_singlefetch 中找到的未来标志。这是因为 .json() 功能在 remix 中已被弃用。

您所要做的就是返回值(在 Remix 中),无需对它们进行 json.stringify 或将它们放入 Response 中。所以将

return Response.json({ error: 'Invalid Form Data', form: action }, { status: 400 })
更改为
return {error: 'Invalid Form Data', form: action}

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