You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Next.js前端展示PostgreSQL Bytea存储的图片?

解决Next.js加载PostgreSQL Bytea图片的方案

1. 修正API路由的字节数据返回逻辑

Prisma从PostgreSQL Bytea字段获取到的是Node.js Buffer类型,直接返回会被序列化成你看到的索引式对象({1:34, 2:90,...}),必须在API层做转换:

方式一:返回Base64字符串(适合小图)

// app/api/images/[id]/route.ts
import { prisma } from '@/lib/prisma';
import { NextResponse } from 'next/server';

export async function GET(_, { params }: { params: { id: string } }) {
  const image = await prisma.image.findUnique({
    where: { id: params.id },
    select: { data: true, mimeType: true },
  });

  if (!image?.data) return new NextResponse('图片不存在', { status: 404 });

  return NextResponse.json({
    base64: image.data.toString('base64'),
    mimeType: image.mimeType
  });
}

方式二:直接返回二进制流(适合6MB这类大图,更高效)

// app/api/images/[id]/route.ts
import { prisma } from '@/lib/prisma';
import { NextResponse } from 'next/server';

export async function GET(_, { params }: { params: { id: string } }) {
  const image = await prisma.image.findUnique({
    where: { id: params.id },
    select: { data: true, mimeType: true },
  });

  if (!image?.data) return new NextResponse('图片不存在', { status: 404 });

  return new NextResponse(image.data, {
    headers: {
      'Content-Type': image.mimeType,
      'Content-Length': image.data.length.toString(),
    },
  });
}

2. 前端组件适配(Next/Image)

适配Base64返回的组件

'use client';
import Image from 'next/image';
import { useEffect, useState } from 'react';

interface ImageRes {
  base64: string;
  mimeType: string;
}

export default function ImageViewer({ params }: { params: { id: string } }) {
  const [imageUrl, setImageUrl] = useState<string | null>(null);

  useEffect(() => {
    fetch(`/api/images/${params.id}`)
      .then(res => res.json())
      .then((data: ImageRes) => {
        setImageUrl(`data:${data.mimeType};base64,${data.base64}`);
      });
  }, [params.id]);

  if (!imageUrl) return <div>加载中...</div>;

  return (
    <div style={{ width: '600px', height: 'auto', position: 'relative' }}>
      <Image
        src={imageUrl}
        alt="数据库加载的图片"
        fill
        sizes="(max-width: 768px) 100vw, 600px"
        style={{ objectFit: 'contain' }}
      />
    </div>
  );
}

适配二进制流返回的组件

需要先在next.config.js配置API路径为允许的图片源:

/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'http',
        hostname: 'localhost', // 生产环境替换为你的域名
        port: '3000',
        pathname: '/api/images/**',
      },
    ],
  },
};

module.exports = nextConfig;

然后编写组件:

import Image from 'next/image';
import { prisma } from '@/lib/prisma';

export default async function ImageViewer({ params }: { params: { id: string } }) {
  // 服务器端预校验图片存在性
  const image = await prisma.image.findUnique({
    where: { id: params.id },
    select: { id: true },
  });

  if (!image) return <div>图片不存在</div>;

  return (
    <div style={{ width: '600px', height: 'auto', position: 'relative' }}>
      <Image
        src={`/api/images/${params.id}`}
        alt="数据库加载的图片"
        width={600}
        height={600}
        style={{ objectFit: 'contain' }}
      />
    </div>
  );
}

3. 关键数据转换说明

你控制台看到的索引式对象,是Buffer被JSON序列化后的结果。如果必须在前端处理这种对象,可转成Uint8Array再生成Base64:

function serializedBufferToBase64(serialized: Record<number, number>): string {
  const maxIndex = Math.max(...Object.keys(serialized).map(Number));
  const uint8Arr = new Uint8Array(maxIndex + 1);
  
  Object.entries(serialized).forEach(([key, val]) => {
    uint8Arr[Number(key)] = val;
  });

  return btoa(String.fromCharCode(...uint8Arr));
}

但不建议前端处理6MB的大文件,优先在API层完成转换。

4. Prisma Schema确认

确保字段定义正确,建议同时存储图片MIME类型:

model Image {
  id        String   @id @default(cuid())
  data      Bytes    @db.Bytea // 映射PostgreSQL Bytea类型
  mimeType  String   // 存储image/jpeg、image/png等类型
  createdAt DateTime @default(now())
}

排查要点

  • 确认MIME类型与图片实际格式匹配,错误类型会导致图片无法渲染
  • Base64格式可直接复制到浏览器地址栏测试(如data:image/jpeg;base64,xxxx)
  • 大图片优先用二进制流方式,Base64会额外增加约30%的体积

内容的提问来源于stack exchange,提问作者cudnn_account

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 14:22:12