-
Notifications
You must be signed in to change notification settings - Fork 95
File stored in blob storage can't be reached #470
Description
I'm able to upload png to blob storage (or at least it seems like that 🙈), but when trying to access it I only get:
This site can't be reached.
Currently on: Next 14.0.0 - App Router Route Handlers
I'm rendering a canvas-image to a png. This is the function where I'm sending it to blob-storage
page.tsx:
// Convert the canvas to a Blob object
canvas.toBlob(async (blob) => {
if (!blob) {
throw new Error('Failed to convert canvas to Blob');
}
console.log(blob);
// Send a POST request to the upload endpoint
const response = await fetch(
'/api/poster/upload?filename=filename.png',
{
method: 'POST',
body: blob,
},
);
// Parse the response as JSON
const result = (await response.json()) as PutBlobResult;
// Store the image URL in the component's state
setImageUrl(result.url);
// Log the result
console.log(result);
setIsLoading(false); // End loading
}, 'image/png');In api/poster/upload/route.ts
import { put } from '@vercel/blob';
import { NextResponse } from 'next/server';
export async function POST(request: Request): Promise<NextResponse> {
const { searchParams } = new URL(request.url);
const filename = searchParams.get('filename');
// Read the request body stream into a Buffer
const chunks = [];
if (request.body) {
let reader = request.body.getReader();
let result = await reader.read();
while (!result.done) {
chunks.push(result.value);
result = await reader.read();
}
}
const body = Buffer.concat(chunks);
if (!filename || !request.body) {
return NextResponse.json(
{},
{ status: 404, statusText: 'Missing filename or request body' },
);
}
const blob = await put(filename, body, {
access: 'public',
});
return NextResponse.json(blob);
}Everything seems to be working as espected, but when I click the link I get "This site can't be reached."

When I copy the link into the blob dashboard I get this:

Clicking download gives me the same error. The filesize is however exactly the same as when I rewrite the function to download the png instead (to make sure the png is a real png):
Code example for verifying the png works
canvas.toBlob((blob) => {
if (!blob) {
throw new Error('Failed to convert canvas to Blob');
}
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'filename.png';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}, 'image/png');Running the function then downloads the file in working condition locally.
Previously my route.ts looked like this:
import { put } from '@vercel/blob';
import { NextResponse } from 'next/server';
export async function POST(request: Request): Promise<NextResponse> {
const { searchParams } = new URL(request.url);
const filename = searchParams.get('filename');
console.log(request.body);
if (!filename || !request.body) {
return NextResponse.json(
{},
{ status: 404, statusText: 'Missing filename or request body' },
);
}
const blob = await put(filename, request.body, {
access: 'public',
});
return NextResponse.json(blob);
}but then I got this logged, and it still didn't work:
ReadableStream { locked: false, state: 'readable', supportsBYOB: false }
compared to now when use the chunks I log this instead:
<Buffer 62 6c 6f 62 3a 68 74 74 70 3a 2f 2f 6c 6f 63 61 6c 68 6f 73 74 3a 33 30 30 31 2f 38 34 65 38 62 66 37 38 2d 38 38 32 65 2d 34 62 36 33 2d 62 34 61 33 ... 13 more bytes>
I would expect to download the png when I open the url, but in all the different variants I've tried I just get "This site can't be reached.". This problem might be because of my limited understanding of blob-storage, but it seems similar to #407, where it was commented that we should open a different issue with more details if we still have issues.
I've also tried with the example code from Vercel Blob Next.js Starter like this, but the result is still the same:
import { put } from '@vercel/blob';
import { NextResponse } from 'next/server';
import { customAlphabet } from 'nanoid';
export const runtime = 'edge';
const nanoid = customAlphabet(
'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
7,
); // 7-character random string
export async function POST(req: Request) {
const file = req.body || '';
const contentType = req.headers.get('content-type') || 'text/plain';
const filename = `${nanoid()}.${contentType.split('/')[1]}`;
const blob = await put(filename, file, {
contentType,
access: 'public',
});
return NextResponse.json(blob);
}