You need to enable JavaScript to run this app. Dart HttpServer fetch发DELETE请求后重定向方法异常问题求解
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.21 08:24:09