Flutter HTTP Post 请求未在 Raspberry Pi 上到达 Node-RED

Flutter HTTP Post Request does not reach Node-RED on Raspberry Pi

我正在尝试通过 HTTP(而非 HTTPS)将数据从 Flutter 发送到 Node-RED(到 Raspberry Pi)。 URL http://bierbrauserver.ddns.net 来自 NO-IP (DDNS)。从 Youtube 教程传输到测试服务器工作正常。但是当我将 URL 从“https://reqres.in/api/users”更改为“http://bierbrauserver.ddns.net:1880”时,我在调试 window 中没有得到任何输入节点红色。我尝试在 AndroidManifest.xml 中添加条目 所以允许http,但这也没有解决问题。 此外,我检查了 Raspberry Pi 所在网络的 WLAN 路由器配置中的端口转发。这里配置了 HTTP 和 1880 (Node-RED) 的端口转发。 IP 地址的连接应该没问题,因为我可以从外部端口访问数据库,该端口也位于 Raspberry Pi。难道只能httpS post 请求吗?

Future<UserModel> createUser(String name, String jobTitle)async{

const String Url = "https://reqres.in/api/users";
// const String Url = "https://bierbrauserver.ddns.net:1880";

final response = await http.post(Uri.parse(Url),body:
{
  "name": name,
  "job": jobTitle
});
if (response.statusCode == 201) {
  final String responseString = response.body;
  return userModelFromJson(responseString);
}
else
  {
    print(response.statusCode);
    return UserModel(name:'Fail',job: 'Fail', id: 'Fail', createdAt: DateTime.now());
  }
}

感谢您的帮助。

将您的代码更改为:

final response = await http.post(Uri.parse(Url),body:
{
  "name": name,
  "job": jobTitle
});
if (response.statusCode == 201) {

  final responseString = jsonDecode(_res.body)
  return userModelFromJson(responseString);
}
else
  {
    print(response.statusCode);
    return UserModel(name:'Fail',job: 'Fail', id: 'Fail', createdAt: DateTime.now());
  }
}

问题已解决。程序代码已经被修改,因为我忘记了在问题修复时立即回答问题。问题隐藏在 Node-RED 程序中。在 Node-RED 中选择了错误的节点。 URL 用“/test”扩展,在“http in”节点的 Node-RED 中重复使用。现在一切正常。

供您参考:“Zutat_1”、“Zutat_2”、“Zutat_3”和“Zutat_4”是该程序中的全局变量,因此不必须传递给“createRezept”函数。 此外,应该提到的是,代码中一些不属于英语的元素是用德语执行的。

Future<RezeptModel> createRezept()async{
   const String Url = "http://bierbrauserver.ddns.net:1880/test";

    final response = await http.post(Uri.parse(Url),body:
    {
      "zutat1": Zutat_1.toStringAsFixed(2),
      "zutat2": Zutat_2.toStringAsFixed(2),
      "zutat3": Zutat_3.toStringAsFixed(2),
      "zutat4": Zutat_4.toStringAsFixed(2),
      "createdAt" : DateTime.now().toIso8601String()

    });
    if (response.statusCode == 201) {
      final String responseString = response.body;
      return rezeptModelFromJson(responseString);
    }
    else
      {
        print(response.statusCode);
        return RezeptModel(zutat1:"Fehler",zutat2: "Fehler", zutat3: "Fehler", zutat4: "Fehler",createdAt: DateTime.now());
      }
}

这是用于解析的代码。(这是在一个单独的文件中,在我的例子中名为“Rezept_model.dart”)

import 'dart:convert';

RezeptModel rezeptModelFromJson(String str) => RezeptModel.fromJson(json.decode(str));

String rezeptModelToJson(RezeptModel data) => json.encode(data.toJson());

class RezeptModel {
    RezeptModel({
       required this.zutat1,
       required this.zutat2,
       required this.zutat3,
       required this.zutat4,
       required this.createdAt,
    });

    String zutat1;
    String zutat2;
    String zutat3;
    String zutat4;
    DateTime createdAt;

    factory RezeptModel.fromJson(Map<String, dynamic> json) => RezeptModel(
        zutat1: json["zutat1"],
        zutat2: json["zutat2"],
        zutat3: json["zutat3"],
        zutat4: json["zutat4"],
        createdAt: DateTime.parse(json["createdAt"]),
    );

    Map<String, dynamic> toJson() => {
        "zutat1": zutat1,
        "zutat2": zutat2,
        "zutat3": zutat3,
        "zutat4": zutat4,
        "createdAt": createdAt.toIso8601String(),
    };
}

为了完整起见,这里是主程序的全部代码。

import 'dart:convert';
import 'dart:math';

import 'package:bier_brau_project/variables.dart';
import 'package:bier_brau_project/rezept_model.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

void main() {

  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Bier Brau App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'HTTP Test Site'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;


  @override
  State<MyHomePage> createState() => _MyHomePageState();
}


 Future<RezeptModel> createRezept()async{
   const String Url = "http://bierbrauserver.ddns.net:1880/test";

    final response = await http.post(Uri.parse(Url),body:
    {
      "zutat1": Zutat_1.toStringAsFixed(2),
      "zutat2": Zutat_2.toStringAsFixed(2),
      "zutat3": Zutat_3.toStringAsFixed(2),
      "zutat4": Zutat_4.toStringAsFixed(2),
      "createdAt" : DateTime.now().toIso8601String()

    });
    if (response.statusCode == 201) {
      final String responseString = response.body;
      return rezeptModelFromJson(responseString);
    }
    else
      {
        print(response.statusCode);
        return RezeptModel(zutat1:"Fehler",zutat2: "Fehler", zutat3: "Fehler", zutat4: "Fehler",createdAt: DateTime.now());
      }
}


class _MyHomePageState extends State<MyHomePage> {

  RezeptModel _rezept = RezeptModel(zutat1: "init", zutat2: "init", zutat3: "init",zutat4: "init", createdAt: DateTime.now());


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children:  <Widget>[
             MySlider(Min:22.0,Max:40.0,Devisions: 100,unit:'l',title: 'Wasser',ID:1),
             MySlider(Min:4.0,Max:20.0,Devisions: 100,unit:'kg',title:'Malz',ID: 2,),
             MySlider(Min:60.0,Max:300.0,Devisions: 100,unit:'g',title:'Hopfen',ID: 3,),
             MySlider(Min:12.0,Max:60.0,Devisions: 100,unit:'g',title:'Hefe',ID:4),
             const SizedBox(height:32.0,),

            Text( "Wasser "+ _rezept.zutat1 +"\n"
                +"Malz "+_rezept.zutat2 +"\n"
                +"Mopfen "+ _rezept.zutat3 +"\n"
               +"Hefe "+ _rezept.zutat4 +"\n"
                +"ist Erfolgreich übertragen worden "
                + _rezept.createdAt.toIso8601String())


          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: ()async{
          final RezeptModel rezept= await createRezept();
          setState(() {
              _rezept=rezept;
          });
        },
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}










/// This is the stateful widget that the main application instantiates.
class MySlider extends StatefulWidget {
  MySlider({Key? key,required this.Min, required this.Max,required this.Devisions,required this.unit,required this.title,required this.ID}): super(key: key);

  final double Min;
  final double Max;
  final String unit;
  final String title;
  final int Devisions;
  final int ID;
  bool ValueChanged= false;


  @override
  State<MySlider> createState() => _MySliderState();
}

/// This is the private State class that goes with MyStatefulWidget.
class _MySliderState extends State<MySlider> {

  double _currentSliderValue =0;

  @override
  Widget build(BuildContext context) {
    return Padding (
      padding: const EdgeInsetsDirectional.fromSTEB(32.0, 32.0, 32.0, 16.0),
        child: Column(children: <Widget> [
          Text(
            widget.title,
            style:  const TextStyle(
                color: Colors.black54,
                height: 1,
                fontSize: 18
            ),

          ),

          Slider(
         value: widget.ValueChanged== false ? ((widget.Max-widget.Min)/2)+widget.Min : _currentSliderValue,
          min: widget.Min,
          max: widget.Max,
          divisions: widget.Devisions,
          label: _currentSliderValue.toStringAsFixed(2),
          onChanged: (double value) {
            setState(() {
              _currentSliderValue = value;
              first_call = false;
              widget.ValueChanged =true;
              switch(widget.ID) {
                case 1: {Zutat_1 =double.parse(value.toStringAsFixed(2));}
                break;

                case 2: {Zutat_2 =double.parse(value.toStringAsFixed(2));}
                break;

                case 3: {Zutat_3 =double.parse(value.toStringAsFixed(2));}
                break;

                case 4: {Zutat_4 =double.parse(value.toStringAsFixed(2));}
                break;

                default: {}
                break;
              }

            });
          },
        ),
          Text(
              (widget.ValueChanged== false ?((widget.Max-widget.Min)/2)+widget.Min : _currentSliderValue.toStringAsFixed(2)).toString() + ' '+widget.unit,
          ),

        ])
        );
  }
}

非常感谢所有处理过这个问题的人。 这里仍然有两张图片存放在连接处以澄清。

Node-RED program to receive from http post

Android Studio emulator with the test application