NodeJS Prisma和Nextjs:内容在重新部署之前不会更新

62lalag4  于 2023-08-04  发布在  Node.js
关注(0)|答案(3)|浏览(174)

下面是我刚刚在Vercel上部署的website。我正在使用Prisma和Next.js构建一个Web应用程序,我遇到了一个问题,内容无法实时更新,直到我手动重新部署应用程序。情况是这样的:

  • 我在Next.js应用程序中有一个API端点,可以从Prisma数据库中获取数据。
  • 当我通过应用程序在数据库中创建或更新数据时,更改会立即反映在开发环境中,但直到我重新部署应用程序后,这些更改才会反映在生产环境中。

这是我在前端获取数据的方式:
第一个月
这是发布内容的API端点:

// Addposts to prisma backend

import { NextResponse, NextRequest } from 'next/server';
import prisma from '../../../prisma/client';

// Function

export async function POST(request:NextRequest) {
    const data = await request.json();
    const title = data.title;
    const user = await prisma.user.findUnique({
        where: {
            email : data.email
        }
    })
    if (!user){
        // return error
        return NextResponse.json({error: "User not found"}, {status: 404})
    }

    if (!title){
        // throw error
        return NextResponse.json({error: "Title is required"}, {status: 400})
    }

    if (title.length > 300){
        return NextResponse.json({error:"Title should not be more than 300 characters"}, {status:400});
    }
    const userId = user?.id;

    const post = await prisma.post.create({
        data: {
            title,
            userId
        }
    })
    try{
        return NextResponse.json({post},{status:200})
    }catch(error){
        return NextResponse.json({error}, {status:500})
    }
}

字符串
获取所有帖子的API端点:

import { NextRequest, NextResponse } from 'next/server'
import prisma from '../../../prisma/client'
import { NextApiResponse } from 'next';

export async function GET(request:NextRequest){
    const posts = await prisma.Post.findMany({
        include: {
            user: true
        },
        orderBy:{
            createdAt: 'desc'
        }
    })
    try{
        // return all the posts
        return NextResponse.json({posts},{status:200})
    }catch(error){
        return NextResponse.json(error, {status:500});
    }
}


如何确保内容更新立即反映在生产环境中,而无需手动重新部署?
下面是GitHub存储库的link

更新

  • 我能够发出POST请求并对数据库进行更改,我认为问题在于GET请求,因为即使在刷新页面时,数据也似乎是静态的。*

以下是我在Vercel上的运行时日志:


的数据

km0tfn4u

km0tfn4u1#

好了,经过几天的调试,这是为我工作的:
我将GET和POST函数移到了一个route.ts文件中。

之前:

这是我如何完成GET请求的:axios.get(url/api/getPosts)和我的POST请求axios.post(url/api/addPosts)

之后:

这是我如何完成GET请求的:axios.get(url/api/Posts)和我的POST请求axios.post(url/api/Posts)

shyt4zoc

shyt4zoc2#

const { data: posts, error } = useSWR( /API/getPost , fetcher, {refreshInterval:1000});
这意味着你正在使用SWR,这是用于数据获取的React钩子。
我看到SWR有一个mutation function,这将是有趣的:您可以使用SWR的mutate()函数来更新缓存并重新获取数据。
在您的存储库Sadeedpv/tweet-it中,我看到您有一个app/components/InputField.tsx,它处理提交功能。它向/api/addPosts端点发出POST请求
您可以修改handleSubmit函数,以便在创建post后也重新验证SWR缓存,如下所示:

import { mutate } from 'swr'; // <-- import mutate from SWR

// ...

const handleSubmit = async (e: React.FormEvent) => {
  e.preventDefault();
  setPost('');
  setDisabled(true);
  toast('Posting...');

  try {
    await axios.post("/api/addPosts", {
      title: post,
      email: session?.user?.email,
    });

    mutate('/api/getPosts'); // <-- revalidate SWR cache here

    setDisabled(false);
    toast.success('Successfully posted');
  } catch (err) {
    toast.error(err.response.data.error);
  }
};

// ...

字符串
通过调用mutate('/api/getPosts'),您将告诉SWR重新验证/api/getPosts端点上的数据。这应该可以确保在成功创建新帖子后,立即在应用中更新帖子列表。
InputField.tsx组件的其余部分可以保持不变。
当您在InputField组件中调用mutate('/api/getPosts')时,您使用的是“mounted SWR hook using the same key”(/api/getPosts),如SWR文档所示。这意味该高速缓存将被更新,并将触发重新验证,这就是您在这里可能需要的。
这可能比在fetch请求中包含一个“无存储”缓存选项要轻,比如:

const fetcher = async (url: string) => {
  const response = await fetch(url, { cache: 'no-store' });
  const data = await response.json();
  return data.posts;
};


如果你发现你的应用由于Next.js的默认缓存行为而提供陈旧的数据,你可以使用no-store选项绕过该高速缓存,并始终从服务器获取新的数据。
如果数据保持静态,请尝试禁用服务器端缓存,以进行测试:对从Prisma数据库获取数据的特定Next.js API路由执行此操作。您可以通过在服务器端代码中设置适当的Cache-Control头来实现这一点。

export async function GET(request:NextRequest){
    const posts = await prisma.Post.findMany({
        include: {
            user: true
        },
        orderBy:{
            createdAt: 'desc'
        }
    })
    try{
        // return all the posts
        let response = NextResponse.json({posts},{status:200});
        response.headers.set("Cache-Control", "s-maxage=1, stale-while-revalidate")
        return response;
    }catch(error){
        return NextResponse.json(error, {status:500});
    }
}


s-maxage=1, stale-while-revalidate cache-control指令告诉服务器将响应缓存1秒,如果该高速缓存过时,则在后台重新验证缓存的同时处理过时的数据。
参见Rishi Raj Jain中的“Next.js | SWR (Stale While Revalidate) — Introduction”。
此外,还包括:
我想知道这是否与我设置PrismaClient的方式有关
根据Vercel管理无服务器函数示例的方式,可能是Prisma Client的陈旧示例导致了问题。您可以尝试确保为每个请求创建一个新的Prisma Client示例:

import { PrismaClient } from "@prisma/client"

export default function getPrismaClient() {
  const client = new PrismaClient();
  return client;
}


然后在您的API路由中,您将执行以下操作:

import getPrismaClient from '../../../prisma/client'

export async function GET(request:NextRequest){
    const prisma = getPrismaClient();
    const posts = await prisma.Post.findMany({
        include: {
            user: true
        },
        orderBy:{
            createdAt: 'desc'
        }
    })
    ...
}


使用Prisma客户端后,请务必断开连接,以避免任何潜在的连接问题:

...
const posts = await prisma.Post.findMany({
        include: {
            user: true
        },
        orderBy:{
            createdAt: 'desc'
        }
    })
prisma.$disconnect();
...


我尝试了更新的解决方案,但不幸的是,它没有解决我的问题。
然后你需要更多的调试信息:
在API端点中添加console.log语句以跟踪请求和响应。这可以帮助您了解API请求是否正常工作以及响应数据是否符合预期。

export async function GET(request:NextRequest){
    const prisma = getPrismaClient();
    const posts = await prisma.Post.findMany({
        include: {
            user: true
        },
        orderBy:{
            createdAt: 'desc'
        }
    })
    prisma.$disconnect();

    console.log("Posts received from DB:", posts); // Logging the received data from DB

    try{
        // return all the posts
        let response = NextResponse.json({posts},{status:200});
        response.headers.set("Cache-Control", "s-maxage=1, stale-while-revalidate")
        return response;
    }catch(error){
        console.log("GET Request Error:", error); // Logging any potential error
        return NextResponse.json(error, {status:500});
    }
}


注意:无服务器函数的控制台日志(如Vercel的API路由)不会出现在浏览器的控制台中。您需要检查Vercel的功能日志以了解这些信息。您可以通过your Vercel dashboard访问这些日志。
如果您还没有,请尝试使用像Postman这样的工具在本地测试您的API路由。这有助于确定问题是出在代码上还是出在部署环境上。
并确认您的Prisma客户端可以正确连接到您的数据库。您可以在API路由启动时添加一个检查,以查看它们是否可以连接到数据库。

// At the beginning of your API routes
const prisma = getPrismaClient();
await prisma.$connect()
  .then(() => console.log("Connected to DB"))
  .catch(error => console.log("DB Connection Error: ", error));
// ... rest of your code


您还可以将onSuccess和onError回调添加到SWR钩子中,以帮助调试潜在的问题。

const { data: posts, error } = useSWR(`/api/getPosts`, fetcher, {
  refreshInterval: 1000,
  onSuccess: (data) => console.log("Data received by SWR:", data),
  onError: (error) => console.log("SWR Error:", error),
});


根据您收集的信息,可能是API端点、与数据库的连接或客户端的数据处理出现问题。
要添加到OP's solution,请执行以下操作:
SWR和Next.js都有自己的缓存机制:

  • 默认情况下,SWR将缓存它获取的数据,并在组件重新装载、浏览器重新获得焦点或网络重新连接时重新验证(重新获取)数据。
  • Next.js(在SWR之上)具有内置的数据获取和缓存功能。然而,由于该高速缓存对于每个函数是本地的,因此它可能不会跨多个无服务器函数共享状态。

每个端点的Next.js无服务器函数可能已经创建了Prisma客户端的新示例。因此,每个函数中的Prisma客户端可能不知道Prisma客户端在另一个函数中所做的更改。
GETPOST操作合并到一个函数中,可以确保它们共享Prisma客户端的同一个示例,因此两者具有相同的数据库视图。
之前,您有两个独立的端点,一个用于获取帖子(/api/getPosts),另一个用于添加帖子(/api/addPosts)。
在更改之后,您将它们整合到一个端点(/api/Posts)中,该端点同时处理GETPOST请求。
这实际上是RESTful API设计中的一种常见模式,其中单个URL或端点Map到资源,HTTP方法的类型(GETPOSTPUTDELETE等)确定要对该资源采取的操作。
举例来说:

  • GET /api/Posts:获取文章列表
  • POST /api/Posts:创建新帖子

这种方法的好处是它简化了API结构,并且更容易理解每个端点基于标准HTTP方法所做的事情。

jk9hmnmh

jk9hmnmh3#

这是因为GET处理程序没有使用request,并且在生产环境中它是静态生成的(https://nextjs.org/docs/app/building-your-application/routing/router-handlers)。无论你是否使用SWR-你的API处理程序是纯html,它总是保持不变,返回在构建时预取的相同数据。

export const dynamic = "force-dynamic";

字符串
在GET API处理程序中将解决这个问题。

相关问题