-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathroute.ts
113 lines (98 loc) · 2.87 KB
/
route.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import { logger } from '@/app/log/logger';
import { NextResponse } from 'next/server';
import puppeteer, { Browser } from 'puppeteer';
// Global browser instance that will be reused across requests
let browserInstance: Browser | null = null;
// Function to get browser instance
async function getBrowser(): Promise<Browser> {
if (!browserInstance || !browserInstance.isConnected()) {
logger.info('Creating new browser instance...');
browserInstance = await puppeteer.launch({
headless: true,
protocolTimeout: 240000,
args: ['--no-sandbox', '--disable-setuid-sandbox'],
});
}
return browserInstance;
}
export async function GET(req: Request) {
const { searchParams } = new URL(req.url);
const url = searchParams.get('url');
let page = null;
if (!url) {
return NextResponse.json(
{ error: 'URL parameter is required' },
{ status: 400 }
);
}
try {
// Get browser instance
const browser = await getBrowser();
// Create a new page
page = await browser.newPage();
// Set viewport to a reasonable size
await page.setViewport({
width: 1280,
height: 720,
});
// Navigate to URL with increased timeout and more reliable wait condition
await page.goto(url, {
waitUntil: 'domcontentloaded', // Less strict than networkidle0
timeout: 60000, // Increased timeout to 60 seconds
});
// Take screenshot
const screenshot = await page.screenshot({
type: 'png',
fullPage: false,
});
// Always close the page when done
if (page) {
await page.close();
}
// Return the screenshot as a PNG image
return new Response(screenshot, {
headers: {
'Content-Type': 'image/png',
'Cache-Control': 's-maxage=3600',
},
});
} catch (error: any) {
logger.error('Screenshot error:', error);
// Ensure page is closed even if an error occurs
if (page) {
try {
await page.close();
} catch (closeError) {
logger.error('Error closing page:', closeError);
}
}
// If browser seems to be in a bad state, recreate it
if (
error.message.includes('Target closed') ||
error.message.includes('Protocol error') ||
error.message.includes('Target.createTarget')
) {
try {
if (browserInstance) {
await browserInstance.close();
browserInstance = null;
}
} catch (closeBrowserError) {
logger.error('Error closing browser:', closeBrowserError);
}
}
return NextResponse.json(
{ error: error.message || 'Failed to capture screenshot' },
{ status: 500 }
);
}
}
// Handle process termination to close browser
process.on('SIGINT', async () => {
if (browserInstance) {
logger.info('Closing browser instance...');
await browserInstance.close();
browserInstance = null;
}
process.exit(0);
});