无法从 Flutter 向 Firebase 实时数据库发送 post 请求

Can't send post requests from Flutter to Firebase Realtime Database

我是一名 flutter 初学者,我正在 Udemy 学习“Flutter & Dart - 完整指南 [2022 版]”课程(如果你知道我在第 10 节第 242 课“发送 POST 请求”。这是我第一次使用 Firebase 和数据库,我在这个问题上停留了很长一段时间。我们在前面的部分构建了一个基本的商店应用程序,现在我们应该发送一个 Post 当我们向我们的应用程序添加新产品时请求我们的 Firebase 实时数据库。我们应该向我们的数据库添加一些关于产品的基本信息。当我尝试添加新产品时,没有任何反应,我的数据库中没有数据,也没有新的我的应用程序中的产品(在发送 Post 请求后立即以相同的功能向应用程序添加产品)。我的终端没有错误,只有下面一行。

I/flutter (11699): ...

在添加 http 包和编写上一课的 post 请求代码之前,我能够将产品添加到应用程序。这些是我的调试、数据库规则和发送 post 请求的函数。

void addProduct(Product product) {
    final url = Uri.parse(
        'https://flutter-update-ca55a-default-rtdb.firebaseio.com/products.json');

    http.post(
      url,
      body: json.encode({
        'title': product.title,
        'description': product.description,
        'imageUrl': product.imageUrl,
        'price': product.price,
        'isFavorite': product.isFavorite,
      }),
    );
    final newProduct = Product(
        id: DateTime.now().toString(),
        title: product.title,
        description: product.description,
        price: product.price,
        imageUrl: product.imageUrl);
    _items.add(newProduct);
    notifyListeners();
  }

我尝试了课程构造器示例代码,但没有成功。然后我尝试禁用我的防火墙,将我的数据库规则更改为我的问题中所见,仍然是同样的问题。我什至不知道我的代码是否正在与 firebase 通信。

编辑: 有时我也会在我的终端上获得最新的文本,并在下面添加屏幕截图:

Click to see Terminal SS

编辑 2 : 所以我创建了一个空项目来查看我的计算机是否正在与 firebase 通信并且它有效,我从一个单屏应用程序向我的数据库添加了信息.恐怕我的商店应用程序中有一个逻辑错误(很可能在屏幕上我使用了 addProduct 函数)所以我正在 post 输入代码,如果您看到错误请警告我。这是 edit-product-screen,我在其中通过提供商使用 addProduct 功能。

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import '../providers/product.dart';
import '../providers/product_provider.dart';

class EditProductScreen extends StatefulWidget {
  static const String routeName = '/edit-product-screen';
  @override
  State<EditProductScreen> createState() => _EditProductScreenState();
}

class _EditProductScreenState extends State<EditProductScreen> {
  //final _priceFocusNode = FocusNode();
  //final _descriptionFocusNode = FocusNode();
  final _imageUrlController = TextEditingController();
  //final _imageUrlFocusNode = FocusNode();
  final _form = GlobalKey<FormState>();
  var _editedProduct =
      Product(id: '', title: '', description: '', price: 0, imageUrl: '');

  var _isInit = true;
  var _isloading = false;

  var _initValues = {
    'title': '',
    'description': '',
    'price': '',
    'imageUrl': '',
  };

  @override
  void initState() {
    //_imageUrlFocusNode.addListener(_updateImageUrl);
    super.initState();
  }

  @override
  void didChangeDependencies() {
    if (_isInit) {
      final String? productId =
          ModalRoute.of(context)!.settings.arguments as String?;
      if (productId != null) {
        _editedProduct = Provider.of<ProductProvider>(context, listen: false)
            .findbyID(productId);
        _initValues = {
          'title': _editedProduct.title,
          'description': _editedProduct.description,
          'price': _editedProduct.price.toString(),
          // 'imageUrl': _editedProduct.imageUrl,
          'imageUrl': '',
        };
        _imageUrlController.text = _editedProduct.imageUrl;
      }
    }
    _isInit = false;
    super.didChangeDependencies();
  }

  // @override
  // void dispose() {
  //   _imageUrlFocusNode.removeListener(_updateImageUrl);
  //    _priceFocusNode.dispose();
  //   _descriptionFocusNode.dispose();
  //   _imageUrlController.dispose();
  //   _imageUrlFocusNode.dispose();
  //   super.dispose();
  // }

  void _updateImageUrl() {
    // if (!_imageUrlFocusNode.hasFocus) {
    //   if ((!_imageUrlController.text.startsWith('http') &&
    //           !_imageUrlController.text.startsWith('https')) ||
    //       (!_imageUrlController.text.endsWith('.png') &&
    //           !_imageUrlController.text.endsWith('.jpg') &&
    //           !_imageUrlController.text.endsWith('.jpeg'))) {
    //     return;
    //   }
    setState(() {});
    //}
  }

  void _saveForm() {
    final isValid = _form.currentState!.validate();
    if (!isValid) {
      return;
    }
    _form.currentState!.save();
    setState(() {
      _isloading = true;
    });

    if (_editedProduct.id != null) {
      //var olan bir product editleniyor
      Provider.of<ProductProvider>(context, listen: false)
          .updateProduct(_editedProduct.id, _editedProduct);
      setState(() {
        _isloading = false;
      });
      Navigator.of(context).pop();
    } else {
      //yeni bir product oluşturuluyor.
      Provider.of<ProductProvider>(context, listen: false)
          .addProduct(_editedProduct)
          .catchError((error) {
        return showDialog<Null>(
          context: context,
          builder: (ctx) => AlertDialog(
            title: Text('An Error Occured'),
            content: Text(error.toString()),
            actions: [
              FlatButton(
                  onPressed: () {
                    Navigator.of(ctx).pop();
                  },
                  child: Text('Okay'))
            ],
          ),
        );
      }).then((_) {
        setState(() {
          _isloading = false;
        });
        Navigator.of(context).pop();
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Edit Products'),
        actions: [
          IconButton(
            onPressed: _saveForm,
            icon: Icon(Icons.save),
          ),
        ],
      ),
      body: _isloading
          ? Center(
              child: CircularProgressIndicator(),
            )
          : Padding(
              padding: const EdgeInsets.all(16.0),
              child: Form(
                key: _form,
                child: ListView(
                  children: [
                    TextFormField(
                      initialValue: _initValues['title'],
                      decoration: InputDecoration(labelText: 'Title'),
                      validator: (value) {
                        if (value!.isEmpty) {
                          return 'Please enter a title';
                        }
                        return null;
                      },
                      textInputAction: TextInputAction.next,
                      // onFieldSubmitted: (_) {
                      //   FocusScope.of(context).requestFocus(_priceFocusNode);
                      // },
                      onSaved: (value) {
                        _editedProduct = Product(
                          title: value as String,
                          price: _editedProduct.price,
                          description: _editedProduct.description,
                          imageUrl: _editedProduct.imageUrl,
                          id: _editedProduct.id,
                          isFavorite: _editedProduct.isFavorite,
                        );
                      },
                    ),
                    TextFormField(
                      initialValue: _initValues['price'],
                      decoration: InputDecoration(labelText: 'Price'),
                      textInputAction: TextInputAction.next,
                      keyboardType: TextInputType.number,
                      //focusNode: _priceFocusNode,
                      // onFieldSubmitted: (_) {
                      //   FocusScope.of(context).requestFocus(_descriptionFocusNode);
                      // },
                      validator: (value) {
                        if (value!.isEmpty) {
                          return 'Please enter a price';
                        }
                        if (double.tryParse(value) == null) {
                          return 'Please enter a valid number';
                        }
                        if (double.parse(value) <= 0) {
                          return 'Plase enter a number greater than zero';
                        }
                        return null;
                      },
                      onSaved: (value) {
                        _editedProduct = Product(
                          title: _editedProduct.title,
                          price: double.parse(value as String),
                          description: _editedProduct.description,
                          imageUrl: _editedProduct.imageUrl,
                          id: _editedProduct.id,
                          isFavorite: _editedProduct.isFavorite,
                        );
                      },
                    ),
                    TextFormField(
                      initialValue: _initValues['description'],
                      decoration: InputDecoration(labelText: 'Description'),
                      maxLines: 3,
                      validator: (value) {
                        if (value!.isEmpty) {
                          return 'Please enter a description';
                        }
                        if (value.length < 10) {
                          return 'Your description must be longer then 10 characters';
                        }
                        return null;
                      },
                      textInputAction: TextInputAction.next,
                      //focusNode: _descriptionFocusNode,
                      keyboardType: TextInputType.multiline,
                      onSaved: (value) {
                        _editedProduct = Product(
                          title: _editedProduct.title,
                          price: _editedProduct.price,
                          description: value as String,
                          imageUrl: _editedProduct.imageUrl,
                          id: _editedProduct.id,
                          isFavorite: _editedProduct.isFavorite,
                        );
                      },
                    ),
                    Row(
                      crossAxisAlignment: CrossAxisAlignment.end,
                      children: <Widget>[
                        Container(
                          width: 100,
                          height: 100,
                          margin: EdgeInsets.only(top: 8, right: 10),
                          decoration: BoxDecoration(
                            border: Border.all(width: 1, color: Colors.grey),
                          ),
                          child: _imageUrlController.text.isEmpty
                              ? Text('Enter a URL')
                              : FittedBox(
                                  child: Image.network(
                                    _imageUrlController.text,
                                    fit: BoxFit.cover,
                                  ),
                                ),
                        ),
                        Expanded(
                          child: TextFormField(
                            decoration: InputDecoration(labelText: 'Image URL'),
                            validator: (value) {
                              if (value!.isEmpty) {
                                return 'Please enter a image url';
                              }
                              if (!value.startsWith('http') &&
                                  !value.startsWith('https')) {
                                return 'Please enter a valid image url';
                              }
                              return null;
                            },
                            keyboardType: TextInputType.url,
                            textInputAction: TextInputAction.done,
                            controller: _imageUrlController,
                            //focusNode: _imageUrlFocusNode,
                            onFieldSubmitted: (_) {
                              _saveForm();
                            },
                            onSaved: (value) {
                              _editedProduct = Product(
                                title: _editedProduct.title,
                                price: _editedProduct.price,
                                description: _editedProduct.description,
                                imageUrl: value as String,
                                id: _editedProduct.id,
                                isFavorite: _editedProduct.isFavorite,
                              );
                            },
                          ),
                        ),
                      ],
                    )
                  ],
                ),
              ),
            ),
    );
  }
}

这是最新版本的 addProduct 函数

   Future<void> addProduct(Product product) async {
    final url = Uri.parse(
        'https://flutter-update-ca55a-default-rtdb.firebaseio.com/products2.json');
    try {
      final response = await http.post(
        url,
        body: json.encode({
          'title': product.title,
          'description': product.description,
          'imageUrl': product.imageUrl,
          'price': product.price,
          'isFavorite': product.isFavorite,
        }),
      );
      print(json.decode(response.body));
      final newProduct = Product(
          id: DateTime.now().toString(),
          title: product.title,
          description: product.description,
          price: product.price,
          imageUrl: product.imageUrl);
      _items.add(newProduct);
      notifyListeners();
    } catch (error) {
      print(error);
      throw error;
    }
  }

我认为您没有实现 await。在尝试更改您的方法 Future 之后,您能否尝试在开头添加 await http.post 然后它会起作用。

Future<Product> addProduct(Product product) async{
    final url = Uri.parse(
        'https://flutter-update-ca55a-default-rtdb.firebaseio.com/products.json');

    await http.post(
      url,
      body: json.encode({
        'title': product.title,
        'description': product.description,
        'imageUrl': product.imageUrl,
        'price': product.price,
        'isFavorite': product.isFavorite,
      }),
    );

最后,您应该使用 json to dart side 进行解析,并尝试使用工厂方法对您的模型实施 json 编码。 (我已经将我的第一个 post 添加到您的后端,请不要忘记为每个人更改写入规则)

如果您想了解更多详情,请查看dart.pad 样品:

https://dartpad.dev/?id=c04e9842d98ac871988973df025c097e