【问题标题】:Flutter how to upload a photo to REST APIFlutter 如何将照片上传到 REST API
【发布时间】:2021-06-06 10:23:37
【问题描述】:

我需要将带有标题和用户名的图像上传到使用 Django 构建的 API。在 Django 中创建 Post 视图标记为 @permission_classes((IsAuthenticated,))。这是代码:

@permission_classes((IsAuthenticated,))
class PostCreateAPIView(CreateAPIView):
    serializer_class = PostSerializer

    def get_queryset(self):
        return Post.objects.all()

序列化器:

class PostSerializer(ModelSerializer):
    class Meta:
        model = Post
        fields = ('author', 'description', 'image', 'created_at')

我做了一些研究,发现由于只有经过身份验证的用户才能发布图片,我需要以某种方式使用用户在登录时收到的令牌。

我在登录时获取了用户令牌,并且能够使用 hive 将其保存在本地。但是我不知道下一步该做什么。

static Future<dynamic> loginUser(String username, String password) async {
    final response = await http.post("$apiURL/en/api/users/login/", body: {
      "username": username,
      "password": password,
    });

    return response?.body;
  }

这是我的登录代码,它返回带有用户名、user_id 和令牌的 json 格式。像这样的:

{
    "token": "dc9e0de8fa2eaa917657e810db06aad2458e4f65",
    "user_id": 4,
    "username": "maria"
}

【问题讨论】:

  • 对于使用 api 发送文件,您可以按照以下步骤操作:stackoverflow.com/a/51162343/4723045 并在登录后使用共享首选项保存用户令牌,因为使用 Hive 仅保存令牌将是过度杀伤力。您可以前往此处保存和读取共享首选项中的数据stackoverflow.com/a/54031842/4723045
  • 谢谢。第一个链接很有用。但是它们不包括使用令牌的授权(
  • 如果对您有帮助,请将我的答案标记为已选答案
  • 谢谢。我猜它正在工作。现在,当我上传图片时,它会返回 html 标签,上面写着 413 Request Entity Too Large。我想我必须在发送之前压缩图像。

标签: flutter django-rest-framework http-post


【解决方案1】:

合并我在 cmets 中给出的建议。

编写此代码以同时添加带有身份验证令牌和文件的标头:

upload(File imageFile, String token) async {    
      // open a bytestream
      var stream = new http.ByteStream(DelegatingStream.typed(imageFile.openRead()));
      // get file length
      var length = await imageFile.length();

      // string to uri
      var uri = Uri.parse("http://ip:8082/composer/predict");

      // create multipart request
      var request = new http.MultipartRequest("POST", uri);

      // add headers with Auth token
      Map<String, String> headers = { "Authorization": "Token $token"};

      request.headers.addAll(headers);

      // multipart that takes file
      var multipartFile = new http.MultipartFile('file', stream, length,
          filename: basename(imageFile.path));

      // add file to multipart
      request.files.add(multipartFile);

      // send
      var response = await request.send();
      print(response.statusCode);

      // listen for response
      response.stream.transform(utf8.decoder).listen((value) {
        print(value);
      });
    }

【讨论】:

  • 我收到 401 错误说 {"detail":"Authentication credentials were not provided."}。关于如何解决这个问题的任何想法?我认为令牌传递不正确。
  • @Davrick 请分享您的代码。您如何将令牌添加到 api 和文件?
  • var uri = Uri.parse("$baseURL/posts/create/"); var request = new http.MultipartRequest("POST", uri); Map&lt;String, String&gt; headers = { "Authorization": "Token ${box.get('token')}" }; request.headers.addAll(headers); var multipartFile = new http.MultipartFile('file', stream, length, filename: path.basename(_image.path)); request.files.add(multipartFile); var response = await request.send(); print(response.statusCode); response.stream.transform(utf8.decoder).listen((value) { print(value); });
  • 大家好,令牌正在工作,但我现在遇到了这个小问题。当我发送上述请求时。我收到回复说"image":["No file was submitted."]
  • 我想您需要与您的后端开发人员核实此响应。您用于发送文件的图像密钥不正确,或者后端可能存在问题。
【解决方案2】:

您可能想要做的是在请求标头中传递令牌。像这样的东西应该可以工作:

  static Future<dynamic> loginUser(String username, String password) async {
    final response = await http.post(
      "$apiURL/en/api/users/login/",
      body: {
        "username": username,
        "password": password,
      },
      headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'Authorization': 'Token $token',
      },
    );

    return response?.body;
  }

请注意,标头包含一个名为 Authorization 的字段,这是您传递令牌的地方。包含令牌的字符串中的关键字Token 指定您使用的身份验证类型。如果它不起作用,可能您正在使用另一种授权。

我建议你看看https://www.django-rest-framework.org/api-guide/authentication/

【讨论】:

  • 但是我在发布图片而不是登录时遇到问题。如果我发布图片,它会一样吗?
  • 哦,很抱歉造成误会。我认为@NaveenRao 提供的解决方案将按预期工作。如果没有,请告诉我,我会尽力为您提供其他解决方案
猜你喜欢
  • 1970-01-01
  • 2011-02-03
  • 1970-01-01
  • 1970-01-01
  • 2011-06-29
  • 2021-05-05
  • 2012-08-19
  • 2020-07-08
  • 1970-01-01
相关资源
最近更新 更多