-
Hi, I noticed that when my |
Beta Was this translation helpful? Give feedback.
Replies: 6 comments 2 replies
-
The public directory isn't a real directory, it's a collection of routes created at build time here: it isn't really supposed to be used for persisted file storage, so the fix would be to use S3/DigitalOcean Spaces/the third party storage solution of your choice. |
Beta Was this translation helpful? Give feedback.
-
we must be able to refresh public routes, its so annoying. i cant be able to do basic file upload in next production |
Beta Was this translation helpful? Give feedback.
-
I made an api route for this purpose. Make a file on Now instead of src for Note: it will not work in subdirs inside of public. If you want that then make new api routes or modify the directory specified
|
Beta Was this translation helpful? Give feedback.
-
I created a new route in /api/assets/[...path].ts, which allows any directory depth, and one that also uses caching to reduce traffic and load. Now I can use urls like
|
Beta Was this translation helpful? Give feedback.
-
For app routers try this, a simplified version of @jasonmcaffee your api file structure should look like this import fs from 'fs';
import { NextResponse } from 'next/server';
export async function GET(req, { params }) {
const dir = params.dir.join("/");
if (!dir) {
return new NextResponse(null, { status: 500 });
}
// Prevent path traversal attacks
if (dir.indexOf('..') >= 0) {
return new NextResponse(null, { status: 400 });
}
try {
// Read and serve the file
const data = fs.readFileSync('public/' + dir,
{flag:'r'}
);
return new NextResponse(data,{status:200});
} catch (error) {
return new NextResponse(null, { status: 500 });
}
} Tags: NextJS App Router, JSX |
Beta Was this translation helpful? Give feedback.
-
@jasonmcaffee I wouldn't risk it with the Here's my version of this in the app router with typescript: import fs from "fs";
import crypto from "crypto";
import { NextResponse } from "next/server";
import path from "path";
export async function GET(
req: Request,
{ params }: { params: Promise<{ path: string[] }> },
) {
const dir = (await params).path.join("/");
const filePath = path.join(process.cwd(), "public", dir);
if (!dir) {
return new NextResponse(null, { status: 500 });
}
console.log(dir, filePath);
// Prevent path traversal attacks
if (dir.indexOf("..") >= 0) {
return new NextResponse(null, { status: 400 });
}
try {
const stats = fs.statSync(filePath);
const lastModified = stats.mtime.toUTCString();
const fileSize = stats.size;
// Generate ETag based on file size and modification time
const eTag = crypto
.createHash("md5")
.update(`${fileSize}-${lastModified}`)
.digest("hex");
// Check if the client has a cached version
if (
req.headers.get("if-none-match") === eTag ||
req.headers.get("if-modified-since") === lastModified
) {
return new NextResponse(null, { status: 304 }); // Not Modified
}
const data = fs.readFileSync("public/" + dir, { flag: "r" });
return new NextResponse(data, {
status: 200,
headers: {
"Cache-Control": "public",
"Last-Modified": lastModified,
ETag: eTag,
},
});
} catch (e) {
if (e instanceof Error) {
if ("code" in e && e.code === "ENOENT") {
return NextResponse.json({ error: "File not found" }, { status: 404 });
}
return NextResponse.json(
{ error: "Failed to read file", message: e.message },
{ status: 500 },
);
} else {
return NextResponse.json(
{ error: "Failed to read file", message: e },
{ status: 500 },
);
}
}
} |
Beta Was this translation helpful? Give feedback.
The public directory isn't a real directory, it's a collection of routes created at build time here:
next.js/packages/next/next-server/server/next-server.ts
Line 775 in ec70096