@@ -348,3 +348,107 @@ public CompletableFuture<String> asyncMethodWithReturn() {
348348}
349349```
350350
351+
352+
353+
354+
355+ ## 2025/11/03 - Knife4j 文档页面空白问题排查与解决
356+
357+ ### 问题
358+
359+ 访问 ` http://localhost:82/doc.html ` 页面显示空白,无法加载 API 文档界面。
360+
361+ 1 . 初步检查配置
362+
363+ - ✅ Knife4j 依赖已正确引入
364+ - ✅ ` application.properties ` 中 Knife4j 配置正确
365+ - ✅ ` GlobalConfigure.java ` 中静态资源映射配置正确
366+ - ✅ API 接口 ` /v3/api-docs ` 可以正常访问(需要 Basic 认证)
367+
368+ 2 . 查看调试日志
369+
370+ 启用调试模式后,发现关键日志:
371+ ``` log
372+ DEBUG o.s.w.s.s.s.WebSocketHandlerMapping : Mapped to WebSocketHttpRequestHandler
373+ DEBUG o.s.w.s.s.s.WebSocketHttpRequestHandler : GET /doc.html
374+ DEBUG o.s.w.s.s.s.HandshakeInterceptorChain : returns false from beforeHandshake
375+ DEBUG o.s.web.servlet.DispatcherServlet : Completed 200 OK
376+ ```
377+
378+ ** 关键发现** :` /doc.html ` 请求被错误地映射到了 WebSocket 处理器,而不是静态资源处理器。
379+
380+ ### 原因
381+
382+ 在 ` WebSocketConfig.java ` 中,WebSocket 处理器使用了过于宽泛的路径模式:
383+
384+ ``` java
385+ registry. addHandler(new WsServerNodeHandler (), " /*" )
386+ ```
387+
388+ #### 为什么会拦截 HTTP 请求?
389+
390+ 1 . Spring MVC 的请求处理流程中,` WebSocketHandlerMapping ` 优先级较高
391+ 2 . ` "/*" ` 模式会匹配所有单层路径,包括:
392+ - ` /doc.html `
393+ - ` /favicon.ico `
394+ - ` /index.html `
395+ - 等等
396+ 3 . 当 WebSocket 处理器匹配上请求后,会检查是否是 WebSocket 握手请求
397+ 4 . 如果不是握手请求,拦截器返回 false,请求直接结束(返回 200 但无内容)
398+ 5 . 静态资源处理器无法处理该请求,导致页面空白
399+
400+ ### 解决方案
401+
402+ #### 修改 WebSocketConfig.java
403+
404+ ** 位置** :` snowy-plugin/snowy-plugin-attack/src/main/java/vip/xiaonuo/attack/modular/config/WebSocketConfig.java `
405+
406+ ** 修改前** :
407+ ``` java
408+ @Override
409+ public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
410+ registry. addHandler(shellWebSocketHandler, " /ws/shell/{sessionId}" )
411+ .setAllowedOrigins(" *" );
412+
413+ registry. addHandler(new WsServerNodeHandler (), " /*" ) // ❌ 错误:拦截所有路径
414+ .addInterceptors(new WsHandshakeInterceptor ())
415+ .setAllowedOrigins(" *" );
416+ }
417+ ```
418+
419+ ** 修改后** :
420+ ``` java
421+ @Override
422+ public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
423+
424+ registry. addHandler(new WsServerNodeHandler (), " /ws/**" ) // ✅ 正确:只拦截 /ws 开头的路径
425+ .addInterceptors(new WsHandshakeInterceptor ())
426+ .setAllowedOrigins(" *" );
427+ }
428+ ```
429+
430+ ### 经验总结
431+
432+ #### 1. WebSocket 路径配置要谨慎
433+ - ❌ 避免使用 ` "/*" ` 或 ` "/**" ` 等宽泛模式
434+ - ✅ 使用明确的路径前缀,如 ` "/ws/**" `
435+
436+ #### 2. 请求映射优先级
437+ Spring MVC 中不同类型的 Handler Mapping 优先级:
438+ 1 . ` WebSocketHandlerMapping ` - 优先级较高
439+ 2 . ` RequestMappingHandlerMapping ` - 处理 @RequestMapping
440+ 3 . ` SimpleUrlHandlerMapping ` - 处理静态资源
441+
442+ #### 3. 调试技巧
443+ 启用 Spring Web 调试日志可以快速定位路由问题:
444+ ``` properties
445+ logging.level.org.springframework.web =DEBUG
446+ logging.level.org.springframework.web.servlet.resource =TRACE
447+ ```
448+
449+ #### 4. Ant 路径模式说明
450+ - ` "/" ` - 只匹配根路径
451+ - ` "/*" ` - 匹配单层路径(如 ` /doc.html ` )
452+ - ` "/**" ` - 匹配多层路径(如 ` /api/user/info ` )
453+ - ` "/ws/**" ` - 只匹配 ` /ws ` 开头的所有路径
454+
0 commit comments