【问题标题】:Can't make my HTTP.GET request with Flutter work properly: OS Error: No address associated with hostname, errno = 7无法使用 Flutter 使我的 HTTP.GET 请求正常工作:操作系统错误:没有与主机名关联的地址,errno = 7
【发布时间】:2021-07-10 17:03:59
【问题描述】:

我对 Flutter 有点陌生。我的请求有什么问题?

我的某个朋​​友配置了一个 SAP Web 服务,而您将在代码中看到的 _kAuth 是这样定义的所需令牌:

static const _kAuth = "Basic $tokenhiddenforprivacy=";

我得到了什么:

  1. 错误:一般错误(下面的屏幕截图)。这只是一个希望错误的令牌的问题吗?我的代码是否存在问题,因为它处理 Null-Safe 错误?
  2. 错误:在第一个错误之后,我得到了这个操作系统错误:没有与主机名关联的地址,errno = 7

主要是:

class CredentialsRecoveryPage extends StatefulWidget {
  const CredentialsRecoveryPage({Key? key}) : super(key: key);

  static const routeName = '/CredentialsRecoveryPage';

  @override
  _CredentialsRecoveryPageState createState() =>
      _CredentialsRecoveryPageState();
}

class _CredentialsRecoveryPageState extends State<CredentialsRecoveryPage> {
  final TextEditingController _emailController = TextEditingController();
  final _formKey = GlobalKey<FormState>();
  bool _alreadyTapped = true;

  @override
  void dispose() {
    _emailController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Scaffold(
        appBar: AppBar(
          elevation: 0,
        ),
        resizeToAvoidBottomInset: true,
        body: Form(
          key: _formKey,
          child: Padding(
            padding: const EdgeInsets.fromLTRB(20, 0, 20, 30),
            child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  Text("Seems like you forgot something...",
                      style: TextStyle(
                        fontSize: 30,
                        fontWeight: FontWeight.w600,
                      )),
                  SizedBox(
                    height: 10,
                  ),
                  Text("We need your mail",
                      style: TextStyle(
                        fontSize: 18,
                        // fontWeight: FontWeight.w500,
                      )),
                  SizedBox(
                    height: 10,
                  ),
                  TextFormField(
                      controller: _emailController,
                      keyboardType: TextInputType.emailAddress,
                      validator: (value) => _validateMail(value!),
                      style: TextStyle(color: Theme.of(context).accentColor),
                      decoration: mailInputDecoration(context),
                      onSaved: (value) => _emailController.text = value!),
                  SizedBox(
                    height: 15,
                  ),
                  Text("The mail will be delivered within 10 minutes",
                      textAlign: TextAlign.center,
                      style: TextStyle(
                        fontSize: 10,
                        // fontWeight: FontWeight.w500,
                      )),
                  Visibility(
                    visible: _alreadyTapped,
                    child: Row(
                        mainAxisAlignment: MainAxisAlignment.end,
                        children: <Widget>[
                          InkWell(
                            onTap: () => _sendCredentialRequest(context),
                            child: Icon(LineIcons.paperPlane,
                                color: Theme.of(context).accentColor),
                          ),
                        ]),
                  ),
                ]),
          ),
        ),
      ),
    );
  }

  String? _validateMail(String mail) {
    if (_emailController.text.isEmpty) {
      return 'Mail field cant\'t be empty';
    } else if (!_emailController.text.toUpperCase().contains("@")) {
      return 'Mail is not valid';
    } else {
      return null;
    }
  }

  Future<dynamic> _sendCredentialRequest(BuildContext ctx) async {
    if (_formKey.currentState!.validate()) {
      startLoadingSpinner(ctx);
      try {
        var resp =
            await NetworkManager().getForCredentials(_emailController.text);
        if (resp.statusCode >= 200 && resp.statusCode <= 300) {
          var message = SapReturnMessage.fromJson(jsonDecode(resp.body));
          Navigator.pop(ctx);
          setState(() {
            _alreadyTapped = false;
          });
          return message.returnSnackByMessage(ctx);
        } else {
          Navigator.pop(ctx);
          SnackBarMessage.genericError(ctx, "Something went wrong!");
        }
      } catch (onError) {
        Navigator.pop(ctx);
        SnackBarMessage.genericError(ctx, onError.toString());
      }
    }
  }
}

然后在我的 networkManager.dart 我有这个 getForCredentials 类:

Future<http.Response> getForCredentials(String mail) async {
    var url =
        "http://mylinkhiddenforprivacy";

    return await http
        .get(Uri.parse(url), headers: {
          "Authorization": _kAuth,
          "Accept": "application/json",
        })
        .then((response) {
          return response;
        })
        .timeout(Duration(seconds: 20))
        .catchError((onError) {
          print(onError.toString());
        });
  }

这是输出: Screenshot

【问题讨论】:

  • 我猜这是因为你没有在 getForCredentials() 函数的 catchError 中返回任何内容
  • 我添加了“return http.Response('', 500);”正如您所建议的那样,我正确地得到了“出了点问题!” “credentialRecoveryPage.dart”代码中的 Snackbar 消息,所以我们可以假设服务器连接的问题可能只是错误的令牌?
  • 您可以为 catchError 提供第二个参数作为 'stacktrace'。将两个 args 打印到控制台以查看实际错误。
  • 如果您不确定令牌测试是否使用 Postman

标签: flutter http dart


【解决方案1】:

编辑:

我找到了答案


我会总结一下我所经历的步骤,这样你就可以做同样的事情,直到其中一个可以帮助你


@Xoltawn 建议是很好的开始,以避免错误。所以我按照建议添加了:

return http.Response("", 500);

实际上真正的问题是另一个问题,类似于您在网上找到的问题(通常):“OS 错误:没有与主机名关联的地址,errno = 7”

我提醒你我需要向一个不是我自己配置​​的 SAP Web Service 发出 http get 请求,我只有 url 和 token --> "Basic $token"

var url = Uri.parse(
        "myurl");

    return await http
        .get(url, headers: {
          "authorization": "Basic $mytoken",
          "Accept": "application/json",
        })

我的问题从这里开始。网络上的每个人都写过关于连接问题的文章,因此他们建议将其添加到主清单文件和调试清单文件中:

  1. 步骤
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

问题没有解决,所以我读到有人修复了更改包,所以:

  1. 步骤

从 HTTP 移动到 DIO package

如果你不修复尝试:

  1. 步骤

使用一些 在线 API 测试工具,例如 reqbin 或 Postman(我使用了 reqbin,我发现它可以更快、更轻松地发出快速 GET 请求,只需使用 URL 和使用“基本 $token”的 CUSTOM 授权" 就像我拥有的​​那样) 以便您确定您的 URL 和 TOKEN 正常工作,真正的问题是 Flutter 和/或包和/或 sintax 错误

如果你不修复尝试:

  1. 步骤

我发现错误与“主机名”有关,所以实际上我的 URL 类似于 http://examplewithoutwww.com:port /.... 所以正常的 HTTP GET 或 DIO GET 无法正常工作,它可能是关于 DNS 配置错误的问题。因此,我尝试使用 Google 更改网址,例如:

var url = Uri.parse(
        "http://www.google.com");

    return await http
        .get(url, headers: {
          "authorization": "Basic $mytoken",
          "Accept": "application/json",
        })
        .then((response) {
          return response;
        })
        .timeout(Duration(seconds: 20))
        .catchError((onError) {
          print(onError.toString());
          return http.Response("", 500);
        });
  }

仍然是同样的错误。所以问题还不是我,但我发现了 --> here 从 Android API 28 和 iOS 9 开始,这些平台默认禁用不安全的 HTTP 连接。 这是解决方案的前 50%

  1. 步骤

添加到您的清单文件:

<application android:usesCleartextTraffic="true"/>

所以现在来自 Google 的 HTTP GET 工作了!但我的 http://examplewithoutwww.com:port/.... 还没有,所以最终解决方案是了解哪个 IP 是我的主机,在我的情况下类似于 http://212.29.432.121/

所以修复它的最后两个步骤是:

  1. 步骤

转到您的模拟器设置(您的虚拟安卓手机右下角的 3 个点 --> 设置 --> 代理)并手动将您的主机名和端口设置为(在我的情况下)http://212.29.432.121/ 以及我在原始 URL 中的 PORT。

  1. 步骤

最终使您的网址类似于:

http://IP/....,请记住WITHOUT网址中的端口!

感谢您的关注,享受!

【讨论】:

    猜你喜欢
    • 2020-11-29
    • 2019-09-28
    • 2021-04-19
    • 2021-08-31
    • 1970-01-01
    • 2020-05-10
    • 1970-01-01
    • 2021-01-20
    • 1970-01-01
    相关资源
    最近更新 更多