IHP框架中redirectTo跳转正常但URL未变更是什么原因?
背景
我有2个控制器:
- LessonsController(包含Index和Show视图)
- QuizAnswersController(无视图)
按照生成的控制器代码规则,LessonsController中的ShowLessonAction会渲染ShowView。
在ShowView中,我放置了一个指向QuizAnswersController对应动作的链接:
<a href={CheckQuizAnswerAction (get #id answer)}>Check Answer</a>
CheckQuizAnswerAction会校验答案是否正确,之后携带提示信息重定向到ShowLessonAction:
action CheckQuizAnswerAction { quizAnswerId } = do quizAnswer <- fetch quizAnswerId quiz <- fetch (get #quizId quizAnswer) let lessonId = get #lessonId quiz case (get #correct quizAnswer) of True -> setSuccessMessage "Correct!" >> redirectTo ShowLessonAction { lessonId } False -> setSuccessMessage "Try again" >> redirectTo ShowLessonAction { lessonId }
问题
所有功能运行正常,但我发现调用CheckQuizAnswerAction后,地址栏URL仍为/CheckQuizAnswer?quizAnswerId=123...,并未变为预期的/ShowLesson?lessonId=123...,请问该现象是什么原因导致的?
原因分析
这个问题是IHP框架默认集成的Turbo Drive特性导致的:
- Turbo Drive会默认接管所有页面导航请求,用fetch请求替换传统的浏览器整页跳转,不会触发整页刷新。
- 你从ShowLesson页面(地址A)点击链接请求CheckQuizAnswerAction(地址B),服务端校验完答案后返回重定向指令回到ShowLessonAction(地址A)。
- Turbo检测到最终要渲染的页面和你最初所在的是同一个页面资源,就只会替换页面的内容(包括你设置的成功/错误提示),不会更新地址栏,所以地址栏就停留在了CheckQuizAnswerAction的路径上。
另外你用GET请求来触发答案校验这类会修改服务端状态的操作,本身也不符合HTTP语义,也是导致该问题的诱因之一。
解决方法
你可以选任意一种方案解决:
- 把校验答案的链接改成POST表单提交,同时给提交按钮加上
data-turbo="false"属性,强制走传统整页跳转,重定向后地址栏就会正常更新。 - 在CheckQuizAnswerAction的重定向逻辑前,添加响应头
Turbo-Replace-Url,值设为ShowLessonAction的完整路径,强制Turbo更新地址栏。 - 调整路由配置,把CheckQuizAnswerAction设置为仅接受POST请求,既符合HTTP语义,也能避免这类GET请求导致的地址栏异常问题。
内容的提问来源于stack exchange,提问作者stephenbenedict
相关产品推荐
相关产品推荐

