Dart HttpServer fetch发DELETE请求后重定向方法异常问题求解
问题原因与解决方案
问题1:重定向后仍为DELETE方法的解决
这个是HTTP标准状态码的行为差异导致的:
- 默认Dart
redirect方法使用的是**302(临时重定向)**状态码,按照规范,对于非GET/HEAD的请求,浏览器会保持原请求方法发起重定向请求,不会自动改为GET。 - 你需要改用**303(See Other)**状态码,这个状态码的规范就是无论原请求方法是什么,重定向请求都会使用GET方法发起。
Dart的redirect方法支持第二个参数指定状态码,修改对应逻辑即可:
if (path == "/thing" && method == "DELETE") { print("delete thing"); await request.response.redirect(Uri( scheme: request.requestedUri.scheme, host: request.requestedUri.host, port: request.requestedUri.port, path: "/deleted"), status: HttpStatus.seeOther, // 指定303状态码 ); return; // 避免执行后面的重复关闭逻辑 }
问题2:重定向后页面不渲染的解决
这个问题出在前端JS逻辑:你用fetch发起的是AJAX异步请求,哪怕配置了redirect: 'follow',浏览器只会把最终的响应内容返回给JS回调,不会主动更新当前页面的内容,也不会自动跳转。
有两种常用的修复方案:
方案1:fetch请求完成后手动跳转页面
不用依赖服务端重定向,请求成功后直接修改浏览器地址跳转即可,逻辑更简单:
修改前端JS部分代码:
form.addEventListener("submit", event => { event.preventDefault(); fetch("/thing", { method: "DELETE" }) .then(response => { // 直接跳转至目标页,默认用GET请求 window.location.href = "/deleted"; }); });
方案2:不使用fetch走浏览器原生提交
如果不想写JS跳转,也可以用后端兼容的方式,用POST表单提交后模拟DELETE逻辑,再由服务端返回303重定向走浏览器原生跳转,相对麻烦更推荐方案1。
完整修复后代码
import 'dart:io'; Future<void> main() async { HttpServer server = await HttpServer.bind(InternetAddress.loopbackIPv4, 8000); await for (HttpRequest request in server) { String path = request.uri.path; String method = request.method; try { if (path == "/" && method == "GET") { print("get home"); request.response.write('home page'); return; } if (path == "/" && method == 'DELETE') { print("delete home"); request.response.write('home page, with delete method'); return; } if (path == "/thing" && method == "GET") { print("get thing"); request.response.headers.contentType = ContentType.html; request.response.write(""" <form action="/thing"> <input type="submit" value="delete"> </form> <script> const form = document.querySelector("form"); form.addEventListener("submit", event => { event.preventDefault(); fetch("/thing", { method: "DELETE" }).then(response => { window.location.href = "/deleted"; }); }); </script>"""); return; } if (path == "/thing" && method == "DELETE") { print("delete thing"); // 此处也可以直接返回200,前端自行跳转即可,重定向不是必须的 await request.response.redirect( Uri( scheme: request.requestedUri.scheme, host: request.requestedUri.host, port: request.requestedUri.port, path: "/deleted" ), status: HttpStatus.seeOther, ); return; } if (path == "/deleted" && method == "GET") { print("get deleted"); request.response.write('deleted thing'); return; } } finally { await request.response.close(); } } }
另外原代码中每个分支已经调用了response.close(),外层还有一个全局的close,会导致重复关闭报错,上述代码用try-finally做了统一处理,避免该问题。
内容的提问来源于stack exchange,提问作者Max888
相关产品推荐
相关产品推荐

