nextjs POST API 不能在实时环境中工作,但在本地环境中工作完美

Posted

技术标签:

【中文标题】nextjs POST API 不能在实时环境中工作,但在本地环境中工作完美【英文标题】:nextjs POSt API not working in live environment, but working perfect on local 【发布时间】:2021-12-08 16:05:41 【问题描述】:

我最近开始学习使用 Nextjs 构建 Web 应用程序,所以我决定构建一个简单的应用程序来玩和学习。我在本地开发,一切都运行良好。但是,当我部署到 vercel 时,POST 功能不起作用。

这个app很简单,在首页显示一些数据,还有一个页面可以输入新数据——使用prisma SQLite。

从数据库中提取数据在主页上工作正常,但是当我尝试插入数据时,它失败并显示以下错误消息;

Failed to load resource: the server responded with a status of 500 ()

还有

adddata:1 Uncaught (in promise) SyntaxError: Unexpected end of JSON input

它与 ENV 变量没有任何关系,因为我没有在这个应用程序上设置任何变量。一切都在我的本地主机上完美运行。 adddata页面的代码请看下面

import Head from 'next/head'
import  useState  from 'react';

import  PrismaClient  from '@prisma/client'
const prisma = new PrismaClient();

export default function AddData(props) 

    const [formData, setFormData] = useState()

    const [responseMessage, setResponseMessage] = useState()

    const [lastEntryMiles, setLastEntryMiles] = useState()
    
    const addLastMillage = () => 
        setLastEntryMiles(props.lastEntry.miles);
        document.getElementById('lastEntry').focus();
    

    async function saveItem(e) 

        e.preventDefault()

        const response = await fetch('/api/addfuelitem/', 
            method: 'POST',
            body: JSON.stringify(formData),
        )
        
        if(!response.ok)
            // throw new Error(response.statusText);
            setResponseMessage(response.statusText);
        
        if(response.ok)

            setResponseMessage("Sucess!!");
            window.setTimeout(function()
                window.location.href = "/";        
            , 2000);
        

        return await response.json()

    

    return (
        <>
            <Head>
                <title>Add Data Fuel Tracker</title>
                <meta name="description" content="Custom Fuel Tracker" />
            </Head>
            <section>
                <div className="container p-5">
                    <div className="text-center"><h2>Add Fuel Data</h2></div>

                    <form onSubmit=saveItem>
                        <div className="mb-3">
                            <label htmlFor="miles" className="form-label">Enter the current millage</label>
                            <input type="number" className="form-control" id="miles" name="miles" onChange=e => setFormData( ...formData, miles: +e.target.value ) />
                        </div>
                        <div className="mb-3">
                            <label htmlFor="volume" className="form-label">Enter the volume of fuel</label>
                            <input type="number"step="0.01" className="form-control" id="volume" name="volume" onChange=e => setFormData( ...formData, volume: +e.target.value ) />
                        </div>
                        <div className="mb-3">
                            <label htmlFor="cost" className="form-label">Enter the total cost of the fuel</label>
                            <input type="number"step="0.01" className="form-control" id="cost" name="cost" onChange=e => setFormData( ...formData, cost: +e.target.value ) />
                        </div>
                        <div className="mb-3">
                            <a className="btn btn-primary" onClick=addLastMillage>Add Last Millage</a>
                        </div>
                        <div className="mb-3">
                            <label htmlFor="lastEntry" className="form-label">Last Millage</label>
                            <input type="number" className="form-control" id="lastEntry" name="lastEntry" defaultValue=props.lastEntry.miles onChange=e => setFormData( ...formData, lastEntry: +e.target.value ) />
                        </div>
                        <div className="mb-3">
                            <label htmlFor="station" className="form-label">Enter the name of the petrol station (optional)</label>
                            <input type="text" className="form-control" id="station" placeholder="Enter the name of the petrol station (optional)" name="station" onChange=e => setFormData( ...formData, station: e.target.value ) />
                        </div>
                        <div className="col-12">
                            <button className="btn btn-primary" type="submit" >Submit form</button>
                        </div>
                        <div className="col-12 responseMessage"> responseMessage </div>
                    </form>
                </div>
            </section>

        </>
    )


export async function getStaticProps()

    const getLastEntry = await prisma.fuelitem.findFirst(
        orderBy: 
          id: 'asc',
        ,
        take: -1, // Reverse the list
    )
  
    return 
      props:
        lastEntry:JSON.parse(JSON.stringify(getLastEntry))
      
    
  

然后下面是api页面

import  PrismaClient  from '@prisma/client'
const prisma = new PrismaClient();

export default async function handler(req, res) 

  const data = JSON.parse(req.body)

  const costLitre = data.cost / data.volume
  const gallons = data.volume * 0.219
  const milesTrip = data.miles - data.lastEntry
  const mpg = milesTrip / gallons

  const savedfuelitem = await prisma.fuelitem.create(
    data:
      miles: data.miles,
      volume: data.volume,
      cost: data.cost,
      station: data.station,
      costLitre: costLitre,
      milesTrip: milesTrip,
      mpg: mpg
    
  )

  res.json(savedfuelitem)
  

编辑以获取更多信息

服务器日志是

[POST] /api/addfuelitem
00:20:39:30
info  - Loaded env from /var/task/.env
2021-10-21T23:20:40.899Z    2e81b793-c28e-4ead-9448-411a4e8c11b7    ERROR   PrismaClientInitializationError: Error querying the database: unable to open database file: /var/task/node_modules/.prisma/client/./data.db
    at cb (/var/task/node_modules/@prisma/client/runtime/index.js:38543:17)
    at async handler (/var/task/.next/server/pages/api/addfuelitem.js:26:25)
    at async Object.apiResolver (/var/task/node_modules/next/dist/server/api-utils.js:101:9)
    at async Server.handleApiRequest (/var/task/node_modules/next/dist/server/next-server.js:770:9)
    at async Object.fn (/var/task/node_modules/next/dist/server/next-server.js:661:37)
    at async Router.execute (/var/task/node_modules/next/dist/server/router.js:205:32)
    at async Server.run (/var/task/node_modules/next/dist/server/next-server.js:841:29)
    at async Server.handleRequest (/var/task/node_modules/next/dist/server/next-server.js:292:20)
    at async Server.<anonymous> (/var/task/___next_launcher.js:32:9) 
  clientVersion: '3.3.0',
  errorCode: undefined

2021-10-21T23:20:40.899Z    2e81b793-c28e-4ead-9448-411a4e8c11b7    ERROR   PrismaClientInitializationError: Error querying the database: unable to open database file: /var/task/node_modules/.prisma/client/./data.db
    at cb (/var/task/node_modules/@prisma/client/runtime/index.js:38543:17)
    at async handler (/var/task/.next/server/pages/api/addfuelitem.js:26:25)
    at async Object.apiResolver (/var/task/node_modules/next/dist/server/api-utils.js:101:9)
    at async Server.handleApiRequest (/var/task/node_modules/next/dist/server/next-server.js:770:9)
    at async Object.fn (/var/task/node_modules/next/dist/server/next-server.js:661:37)
    at async Router.execute (/var/task/node_modules/next/dist/server/router.js:205:32)
    at async Server.run (/var/task/node_modules/next/dist/server/next-server.js:841:29)
    at async Server.handleRequest (/var/task/node_modules/next/dist/server/next-server.js:292:20)
    at async Server.<anonymous> (/var/task/___next_launcher.js:32:9) 
  clientVersion: '3.3.0',
  errorCode: undefined

RequestId: 2e81b793-c28e-4ead-9448-411a4e8c11b7 Error: Runtime exited with error: exit status 1
Runtime.ExitError

但是没有任何响应体,只有响应头

cache-control: s-maxage=0
content-disposition: inline; filename="500"
content-type: text/html; charset=utf-8
date: Thu, 21 Oct 2021 23:20:41 GMT
server: Vercel
strict-transport-security: max-age=63072000; includeSubDomains; preload
x-matched-path: /500
x-vercel-cache: MISS
x-vercel-id: lhr1::964nh-1634858438937-e662abbca7b4

【问题讨论】:

您的服务器日志对 500 错误有何看法?实际的响应正文是什么(使用浏览器的开发工具 Network 面板进行检查) 嗨菲尔,感谢您的评论。我已经用日志和响应编辑了这个问题。如果您有任何想法,我将非常感谢您在这里提供一些建议。干杯 您似乎没有在生产环境中正确配置您的 Prisma 客户端。见prisma.io/docs/concepts/database-connectors/sqlite @Phil 很奇怪,因为它在读取数据时可以在主页上很好地查询数据库。它只是在写入数据时遇到问题。我将不得不进一步研究这个问题,因为我看不到问题 【参考方案1】:

您正在尝试连接到 Vercel 服务器内的 sqlite 数据库/文件。这是不可能的,因为

    您可能尚未初始化 sqlite 数据库。 Vercel 函数在 lambda 中运行,因此它们是非持久性的(您的数据库不希望这样)。

我建议切换到托管数据库解决方案(PostgreSQL、mysql 或 SQL Server)。您可以在Prisma docs 中找到有关部署到 Vercel 的更多信息。

【讨论】:

嘿@Tasin,非常感谢您的回复。那么我将不得不使用 MySQL,再次感谢。 欢迎,乐于助人:)

以上是关于nextjs POST API 不能在实时环境中工作,但在本地环境中工作完美的主要内容,如果未能解决你的问题,请参考以下文章

如何将实时数据输入 NextJS?

如何隐藏通过 url 直接访问的 nextjs api 路由?

Rails - jQuery 不能在 Heroku 的生产环境中工作

NextJS:生产中未定义的上下文值(在开发中工作正常)

为啥我从托管在 Firebase 上的 NextJs 应用程序仅针对 POST 请求收到“502 网关”错误?

请求 REST POST API 在 Postman 中工作,但在 Alamofire 中不起作用