【问题标题】:Flutter - Handle status code 302 in POST requestFlutter - 在 POST 请求中处理状态码 302
【发布时间】:2019-03-03 09:34:18
【问题描述】:

我正在尝试使用 DIO 包在 Flutter 中发送 post 请求。

这是请求:

getSessionId() async {

  var csrf = await getCsrftoken();

  var dio = new Dio(new Options(
      baseUrl: "http://xxxxxxx/accounts/login/",
      connectTimeout: 5000,
      receiveTimeout: 100000,
      // 5s
      headers: {
        'Cookie': "csrftoken=" + csrf
      },
      contentType: ContentType.JSON,
      // Transform the response data to a String encoded with UTF8.
      // The default value is [ResponseType.JSON].
      responseType: ResponseType.PLAIN
  ));

  var response;
  response = await dio.post("http://xxxxxxx/accounts/login/",
    data: {
      "username": "xxxxx",
      "password": "xxxxx",
      "csrfmiddlewaretoken" : csrf
    },
    options: new Options(
        contentType: ContentType.parse("application/x-www-form-urlencoded")),
  );

  print("StatusCode: ");
  print(response.statusCode);
  print("Response cookie: ");   //THESE ARE NOT PRINTED
  print(response.headers);
}

请求后我得到:

E/flutter ( 4567): [ERROR:flutter/shell/common/shell.cc(181)] Dart Error: Unhandled exception:
    E/flutter ( 4567): DioError [DioErrorType.RESPONSE]: Http status error [302]
    E/flutter ( 4567): #0      getSessionId (file:///C:/get_order/lib/main.dart:36:14)
    E/flutter ( 4567): <asynchronous suspension>

从此请求中,我只需要获取sessionid cookie,但函数会因未处理的异常而停止。

【问题讨论】:

    标签: post request dart flutter http-status-code-302


    【解决方案1】:

    我是这样解决的:

    followRedirects: falsevalidateStatus: (status) { return status &lt; 500;} 添加到请求中。像这样:

    var response = await Dio().post("http://myurl",
        data: requestBody,
        options: Options(
            followRedirects: false,
            validateStatus: (status) { return status < 500; }
        ),
    );
    

    这样你就可以从302headers等处获取。

    【讨论】:

    • 可以通过在header中添加Accept type as application/json来解决
    • "Accept" : "application/json" 解决了我的问题。谢谢
    【解决方案2】:

    除非响应代码是 303,否则 Dart HTTP 客户端不会 follow redirects 用于 POST。它遵循 GET 或 HEAD 的 302 重定向。

    您可以查看是否可以停止服务器发送重定向以响应(可能)有效的登录请求,并改为发送 200。

    或者您可以尝试通过将表单字段编码到 URL 中以 GET 形式发送登录请求,例如:

    http://xxxxxxx/accounts/login/?username=xxxx&amp;password=yyyy&amp;csrfmiddlewaretoken=zzzz

    您必须对参数中的任何特殊字符进行 URL 编码。大概,您也想使用 HTTPS。

    最后,该 URL 是否以 / 结尾? /accounts/login 可能值得一试。

    【讨论】:

    • 谢谢。但我只需要此响应中的“sessionid”cookie。
    • 除了重定向位置(由客户端自动处理)之外,您无法从 302 响应中访问任何内容。由于各种原因,客户端正确地不会跟随重定向到 POST。
    • 好的,谢谢!那我只有你写的2种可能性?
    • 是的,先检查URL,然后尝试GET,最后看看服务器是否可以发送200而不是重定向。
    • 只是为了解释为什么会发生这种情况。 http 包严格遵循 HTTP 规范,通过它在 POST 上重定向不应使用 302 而是 303:developer.mozilla.org/en-US/docs/Web/HTTP/…
    【解决方案3】:

    我遇到了类似的问题,我通过添加标题解决了它 "Accept":"application/json" 。以后它只会返回 json 数据,否则会提示使用 html url 重定向。

    【讨论】:

      【解决方案4】:

      302 的重定向是为了响应 GET 或 HEAD 请求,而不是 POST。有时服务器会发送 302 以响应 POST(在我的情况下)。在这种情况下,Dio 会抛出您可以捕获的异常 - 请记住检查服务器状态代码是否为 302,或者可能是另一个错误。

      try{
          await dio.post( _urlLogin,
            data:{...},
            options: Options(
              contentType: ContentType.parse("application/x-www-form-urlencoded"),          
            )
        );
      }on DioError catch(error){
          if(error.response.statusCode == 302){
          // do your stuff here
           }
      

      【讨论】:

        【解决方案5】:

        在我的例子中,这个问题是通过在 post 方法中发送带有标题的 cookie 来解决的

        问题是 API 是用 HTML 登录页面而不是 JSON 数据来响应我的。

        当你执行 si/log - in 时,你会在响应头中找到 cookie 键

        状态错误代码为 302

        【讨论】:

          【解决方案6】:

          我正在尝试将其用于网络抓取...不要问我为什么哈哈。我来自 python/golang,我已经尝试过 http 包,但是我建议你使用 dio 包。

          使用 dio 我正在执行以下操作:

                Scrapers.client = Dio();
                // create a local cookie to handle with sites that force you to use it
                var cookieJar = CookieJar();
                // assign middlewares to be "session like"
                Scrapers.client?.interceptors.add(CookieManager(cookieJar));
                // assign a logging middleware
                Scrapers.client?.interceptors.add(LogInterceptor(responseBody: false));
                // set the default content type to this client
                Scrapers.client?.options.contentType = Headers.formUrlEncodedContentType;
          
          
          ...
          
            static Future<Response> handleRedirects(Response r, int statusCode) async {
              var redirects = 0;
              while (r.statusCode == statusCode) {
                print("redirect #${redirects++}");
                final redirecturl = r.headers['location']![0];
                r = await Scrapers.client!.post(redirecturl,
                    options: Options(
                      followRedirects: false,
                      validateStatus: (status) {
                        return status! < 500;
                    }));
              }
              return r;
            }
          
          ...
          
          
              Response r = await Scrapers.client!.post(url,
                  data: payload,
                  options: Options(
                      followRedirects: false,
                      validateStatus: (status) {
                        return status! < 500;
                      }));
              r = await Scrapers.handleRedirects(r, 302);
          

          注意,这只是一种简单的方法。您可以根据需要进行更改。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2020-10-27
            • 1970-01-01
            • 2019-11-09
            • 2016-12-11
            • 1970-01-01
            • 2013-12-11
            • 1970-01-01
            相关资源
            最近更新 更多