@@ -42,6 +42,33 @@ class Sniffer {
4242 }
4343 }
4444
45+ /**
46+ * 安全的 page.evaluate 调用,处理执行上下文销毁的情况
47+ */
48+ async safeEvaluate ( page , pageFunction , ...args ) {
49+ try {
50+ // 检查页面是否已关闭
51+ if ( page . isClosed ( ) ) {
52+ this . log ( '页面已关闭,跳过 evaluate 调用' ) ;
53+ return null ;
54+ }
55+
56+ return await page . evaluate ( pageFunction , ...args ) ;
57+ } catch ( error ) {
58+ // 处理执行上下文销毁错误
59+ if ( error . message . includes ( 'Execution context was destroyed' ) ||
60+ error . message . includes ( 'Cannot find context' ) ||
61+ error . message . includes ( 'Target closed' ) ) {
62+ this . log ( '执行上下文已销毁,安全跳过 evaluate 调用:' , error . message ) ;
63+ return null ;
64+ }
65+
66+ // 其他错误继续抛出
67+ this . log ( 'evaluate 调用发生错误:' , error . message ) ;
68+ throw error ;
69+ }
70+ }
71+
4572 /**
4673 * 检查是否可以进行 HEAD 请求
4774 */
@@ -363,7 +390,7 @@ class Sniffer {
363390 // 执行页面脚本
364391 if ( script ) {
365392 try {
366- await page . evaluate ( script ) ;
393+ await this . safeEvaluate ( page , script ) ;
367394 this . log ( `网页加载完成后成功执行脚本: ${ script } ` ) ;
368395 } catch ( e ) {
369396 this . log ( `网页加载完成后执行脚本发生错误: ${ e . message } ` ) ;
@@ -403,6 +430,11 @@ class Sniffer {
403430 const headUrls = [ ] ; // 已经 head 请求过的链接
404431 const page = await this . getPage ( headers ) ;
405432
433+ // 外部变量保存嗅探结果,避免依赖页面上下文
434+ let externalRealUrl = '' ;
435+ let externalRealHeaders = { } ;
436+ let sniffingSuccess = false ;
437+
406438 let actualTimeout = timeout || this . timeout ;
407439 if ( mode === 1 ) {
408440 actualTimeout = Math . min ( actualTimeout , this . timeout ) ;
@@ -412,12 +444,19 @@ class Sniffer {
412444
413445 // 请求拦截器
414446 const onRequest = async ( request ) => {
415- const url = request . url ( ) ;
416- const method = request . method ( ) ;
417- const requestHeaders = request . headers ( ) ;
418- const resourceType = request . resourceType ( ) ;
419-
420- this . log ( 'on_request:' , url , ' method:' , method , ' resource_type:' , resourceType ) ;
447+ try {
448+ // 检查页面是否已关闭
449+ if ( page . isClosed ( ) ) {
450+ this . log ( '页面已关闭,跳过请求处理' ) ;
451+ return false ;
452+ }
453+
454+ const url = request . url ( ) ;
455+ const method = request . method ( ) ;
456+ const requestHeaders = request . headers ( ) ;
457+ const resourceType = request . resourceType ( ) ;
458+
459+ this . log ( 'on_request:' , url , ' method:' , method , ' resource_type:' , resourceType ) ;
421460
422461 // 检查排除正则
423462 if ( snifferExclude && new RegExp ( snifferExclude , 'mi' ) . test ( url ) ) {
@@ -432,7 +471,13 @@ class Sniffer {
432471
433472 realUrls . push ( { url, headers : _headers } ) ;
434473
435- await page . evaluate ( ( [ url , _headers , realUrls ] ) => {
474+ // 保存到外部变量
475+ externalRealUrl = url ;
476+ externalRealHeaders = _headers ;
477+ sniffingSuccess = true ;
478+
479+ // 尝试设置页面变量(可能失败但不影响结果)
480+ await this . safeEvaluate ( page , ( [ url , _headers , realUrls ] ) => {
436481 window . realUrl = url ;
437482 window . realHeaders = _headers ;
438483 window . realUrls = realUrls ;
@@ -457,7 +502,13 @@ class Sniffer {
457502
458503 realUrls . push ( { url, headers : _headers } ) ;
459504
460- await page . evaluate ( ( [ url , _headers , realUrls ] ) => {
505+ // 保存到外部变量
506+ externalRealUrl = url ;
507+ externalRealHeaders = _headers ;
508+ sniffingSuccess = true ;
509+
510+ // 尝试设置页面变量(可能失败但不影响结果)
511+ await this . safeEvaluate ( page , ( [ url , _headers , realUrls ] ) => {
461512 window . realUrl = url ;
462513 window . realHeaders = _headers ;
463514 window . realUrls = realUrls ;
@@ -501,7 +552,13 @@ class Sniffer {
501552
502553 realUrls . push ( { url, headers : _headers } ) ;
503554
504- await page . evaluate ( ( [ url , _headers , realUrls ] ) => {
555+ // 保存到外部变量
556+ externalRealUrl = url ;
557+ externalRealHeaders = _headers ;
558+ sniffingSuccess = true ;
559+
560+ // 尝试设置页面变量(可能失败但不影响结果)
561+ await this . safeEvaluate ( page , ( [ url , _headers , realUrls ] ) => {
505562 window . realUrl = url ;
506563 window . realHeaders = _headers ;
507564 window . realUrls = realUrls ;
@@ -526,6 +583,19 @@ class Sniffer {
526583 }
527584
528585 return false ;
586+ } catch ( error ) {
587+ // 全局错误处理
588+ if ( error . message . includes ( 'Execution context was destroyed' ) ||
589+ error . message . includes ( 'Cannot find context' ) ||
590+ error . message . includes ( 'Target closed' ) ||
591+ error . message . includes ( 'Page closed' ) ) {
592+ this . log ( '请求处理过程中页面上下文已销毁,安全跳过:' , error . message ) ;
593+ return false ;
594+ }
595+
596+ this . log ( '请求处理过程中发生错误:' , error . message ) ;
597+ return false ;
598+ }
529599 } ;
530600
531601 // 监听请求
@@ -539,7 +609,7 @@ class Sniffer {
539609 await page . exposeFunction ( 'log' , ( ...args ) => console . log ( ...args ) ) ;
540610
541611 // 初始化页面变量
542- await page . evaluate ( ( ) => {
612+ await this . safeEvaluate ( page , ( ) => {
543613 window . realUrl = '' ;
544614 window . realHeaders = { } ;
545615 window . realUrls = [ ] ;
@@ -598,7 +668,7 @@ class Sniffer {
598668 ` ;
599669
600670 await page . evaluateOnNewDocument ( jsCode ) ;
601- await page . evaluate ( jsCode ) ;
671+ await this . safeEvaluate ( page , jsCode ) ;
602672 this . log ( `网页加载完成后成功执行脚本: ${ script } ` ) ;
603673 } catch ( e ) {
604674 this . log ( `网页加载完成后执行脚本发生错误: ${ e . message } ` ) ;
@@ -610,10 +680,18 @@ class Sniffer {
610680 // 等待结果
611681 if ( mode === 0 ) {
612682 try {
613- await page . waitForFunction ( ( ) => window . realUrl , { timeout : actualTimeout } ) ;
683+ // 优先检查外部变量,如果已经有结果就不需要等待
684+ if ( ! sniffingSuccess ) {
685+ await page . waitForFunction ( ( ) => window . realUrl , { timeout : actualTimeout } ) ;
686+ } else {
687+ this . log ( '外部变量已有嗅探结果,跳过等待' ) ;
688+ }
614689 } catch ( e ) {
615690 this . log ( `page.waitForFunction window.realUrl 发生了错误: ${ e . message } ` ) ;
616- isTimeout = true ;
691+ // 即使等待失败,也检查外部变量是否有结果
692+ if ( ! sniffingSuccess ) {
693+ isTimeout = true ;
694+ }
617695 }
618696 } else if ( mode === 1 ) {
619697 try {
@@ -624,10 +702,17 @@ class Sniffer {
624702 }
625703 }
626704
627- // 获取结果
628- const realUrl = await page . evaluate ( ( ) => window . realUrl ) ;
629- const realHeaders = await page . evaluate ( ( ) => window . realHeaders ) ;
630- const realUrlsResult = await page . evaluate ( ( ) => window . realUrls ) ;
705+ // 获取结果 - 优先使用外部变量
706+ let realUrl = externalRealUrl || '' ;
707+ let realHeaders = externalRealHeaders || { } ;
708+ let realUrlsResult = realUrls || [ ] ;
709+
710+ // 如果外部变量没有结果,再尝试从页面获取
711+ if ( ! realUrl ) {
712+ realUrl = await this . safeEvaluate ( page , ( ) => window . realUrl ) || '' ;
713+ realHeaders = await this . safeEvaluate ( page , ( ) => window . realHeaders ) || { } ;
714+ realUrlsResult = await this . safeEvaluate ( page , ( ) => window . realUrls ) || [ ] ;
715+ }
631716
632717 const cost = Date . now ( ) - startTime ;
633718 const costStr = `${ cost } ms` ;
0 commit comments