1
1
import type { H3Error , H3Event } from 'h3'
2
+ import type { FetchResponse , FetchOptions } from 'ofetch'
2
3
import type {
3
4
OgImageOptions ,
4
5
OgImageRenderEventContext ,
@@ -19,6 +20,7 @@ import { decodeObjectHtmlEntities } from '../util/encoding'
19
20
import { createNitroRouteRuleMatcher } from '../util/kit'
20
21
import { normaliseOptions } from '../util/options'
21
22
import { useChromiumRenderer , useSatoriRenderer } from './instances'
23
+ import { logger } from "#og-image/server/util/logger" ;
22
24
23
25
export function resolvePathCacheKey ( e : H3Event , path ?: string ) {
24
26
const siteConfig = e . context . siteConfig . get ( )
@@ -64,9 +66,9 @@ export async function resolveContext(e: H3Event): Promise<H3Error | OgImageRende
64
66
const key = resolvePathCacheKey ( e , basePath )
65
67
let options : OgImageOptions | null | undefined = queryParams . options as OgImageOptions
66
68
if ( ! options ) {
67
- if ( import . meta. prerender )
68
- options = await prerenderOptionsCache ? .getItem ( key )
69
-
69
+ if ( import . meta. prerender ) {
70
+ options = await prerenderOptionsCache ! . getItem ( key )
71
+ }
70
72
if ( ! options ) {
71
73
const payload = await fetchPathHtmlAndExtractOptions ( e , basePath , key )
72
74
if ( payload instanceof Error )
@@ -189,6 +191,24 @@ export function extractAndNormaliseOgImageOptions(html: string): OgImageOptions
189
191
return payload
190
192
}
191
193
194
+ function handleNon200Response ( res : FetchResponse < string > , path : string ) {
195
+ let errorDescription
196
+ // if its a redirect let's get the redirect path
197
+ if ( res . status >= 300 && res . status < 400 ) {
198
+ errorDescription = `${ res . status } redirected to ${ res . headers . get ( 'location' ) || 'unknown' } `
199
+ }
200
+ else if ( res . status >= 400 ) {
201
+ // try get the error message from the response
202
+ errorDescription = `${ res . status } error: ${ res . statusText } `
203
+ }
204
+ if ( errorDescription ) {
205
+ return createError ( {
206
+ statusCode : 500 ,
207
+ statusMessage : `[Nuxt OG Image] Failed to parse \`${ path } \` for og-image extraction. ${ errorDescription } ` ,
208
+ } )
209
+ }
210
+ }
211
+
192
212
// TODO caching
193
213
async function fetchPathHtmlAndExtractOptions ( e : H3Event , path : string , key : string ) : Promise < H3Error | OgImageOptions > {
194
214
const cachedHtmlPayload = await htmlPayloadCache . getItem ( key )
@@ -198,41 +218,46 @@ async function fetchPathHtmlAndExtractOptions(e: H3Event, path: string, key: str
198
218
// extract the payload from the original path
199
219
let _payload : string | null = null
200
220
let html : string
201
- try {
202
- html = await e . $fetch ( path , {
203
- // follow redirects
204
- redirect : 'follow' ,
205
- headers : {
206
- accept : 'text/html' ,
207
- } ,
208
- } )
209
- _payload = getPayloadFromHtml ( html )
210
- // fallback to globalThis.fetch
211
- if ( ! _payload ) {
212
- const fallbackHtml = await globalThis . $fetch ( path , {
213
- // follow redirects
214
- redirect : 'follow' ,
215
- headers : {
216
- accept : 'text/html' ,
217
- } ,
218
- } )
219
- _payload = getPayloadFromHtml ( fallbackHtml )
220
- if ( _payload ) {
221
- html = fallbackHtml
222
- }
221
+ const fetchOptions : FetchOptions = {
222
+ // follow redirects
223
+ redirect : 'follow' ,
224
+ ignoreResponseError : true ,
225
+ headers : {
226
+ accept : 'text/html' ,
227
+ } ,
228
+ } as const
229
+ const htmlRes = await e . fetch ( path , fetchOptions )
230
+ const err = handleNon200Response ( htmlRes , path )
231
+ if ( err ) {
232
+ logger . warn ( err )
233
+ }
234
+ html = await htmlRes . text ( )
235
+ _payload = getPayloadFromHtml ( html )
236
+ // fallback to globalThis.fetch
237
+ if ( ! _payload ) {
238
+ const fallbackHtmlRes = await globalThis . $fetch . raw ( path , fetchOptions )
239
+ const err = handleNon200Response ( fallbackHtmlRes , path )
240
+ if ( err ) {
241
+ return err
242
+ }
243
+ const fallbackHtml = await fallbackHtmlRes . text ( )
244
+ _payload = getPayloadFromHtml ( fallbackHtml )
245
+ if ( _payload ) {
246
+ html = fallbackHtml
223
247
}
224
248
}
225
- catch ( err ) {
249
+
250
+ if ( ! html ) {
226
251
return createError ( {
227
252
statusCode : 500 ,
228
- statusMessage : `[Nuxt OG Image] Failed to read the path ${ path } for og-image extraction. ${ err . message } .` ,
253
+ statusMessage : `[Nuxt OG Image] Failed to read the path ${ path } for og-image extraction, returning no HTML .` ,
229
254
} )
230
255
}
231
256
232
- if ( ! _payload || ! html ) {
257
+ if ( ! _payload ) {
233
258
return createError ( {
234
259
statusCode : 500 ,
235
- statusMessage : `[Nuxt OG Image] Got invalid response from ${ path } for og-image extraction .` ,
260
+ statusMessage : `[Nuxt OG Image] HTML response from ${ path } is missing the #nuxt- og-image-options script tag. Check you have used defined an og image for this page .` ,
236
261
} )
237
262
}
238
263
0 commit comments