【问题标题】:PUT request with Retrofit doesn't get through but curl does使用 Retrofit 的 PUT 请求无法通过,但 curl 可以
【发布时间】:2020-06-18 19:26:14
【问题描述】:

我想从一个带有 Retrofit 的 Android 应用程序向我的 Flask API 发送一个 PUT 请求,它应该更新一个 MongoDB 文档。使用整个 URL 运行 curl 命令可以正常工作,但是当我运行改造功能时没有任何反应。

查看来自服务器的日志,我可以看到我的所有 GET 请求,但看不到我的 PUT 请求。

烧瓶 | [2020-06-18 19:07:16 +0000] [19] [调试] GET /beers/all
烧瓶| 高分辨率照片| CLIPARTO [2020-06-18 19:07:30 +0000] [20] [调试] GET /beers/by_barcode
烧瓶| 高分辨率照片| CLIPARTO [2020-06-18 19:07:30 +0000] [10] [调试] GET /beers/by_id

当我使用这个 curl 命令时

curl -X PUT 'http://0.0.0.0:5000/users/add_scanned?user_id=test2&beer_id=test2C&beer_name=test2&img_link=http://test2'

一切正常,我看到了这些日志:

烧瓶 | [2020-06-18 19:26:49 +0000] [11] [调试] PUT /users/add_scanned
烧瓶| 高分辨率照片| CLIPARTO [2020-06-18 19:26:49 +0000] [11] [INFO] 添加啤酒扫描

Mongo 不会记录任何奇怪的东西。另一个使用 Retrofit 的 PUT 请求非常有效。

烧瓶 | [2020-06-18 19:10:38 +0000] [20] [DEBUG] PUT /beers/update_barcode

这是我的代码。

Android 改造 API

import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import retrofit2.Call
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import retrofit2.converter.scalars.ScalarsConverterFactory
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.PUT
import retrofit2.http.Query


private const val BASE_URL = "http://***.***.**.*:5000/"

private val moshi = Moshi.Builder()
    .add(KotlinJsonAdapterFactory())
    .build()

private val retrofit = Retrofit.Builder()
    .addConverterFactory(ScalarsConverterFactory.create())
    .addConverterFactory(MoshiConverterFactory.create(moshi))
    .baseUrl(BASE_URL)
    .build()

interface UserApiService {

    /**
     * Adds a beer to scanned list
     */
    @PUT("users/add_scanned")
    fun addScanned(
        @Query("user_id") userId: String,
        @Query("beer_id") beerId: String,
        @Query("beer_name") beerName: String
        ):
            Call<String>
    }

烧瓶蓝图

from flask import Blueprint, jsonify, request, abort
from bson.objectid import ObjectId
from pymongo import MongoClient
from flask import current_app

bp = Blueprint('users', __name__, url_prefix='/users')
client = MongoClient(host="mongo", username="*****", password="*****")
db = client.TeddyMongo
collection = db.users

def to_dict(document):
    document["_id"] = str(document["_id"])
    return document

# When a user is not found
@bp.errorhandler(404)
def user_not_found(e):
    return jsonify(error=str(e)), 404

# Add beer scanned
@bp.route('/add_scanned', methods=['PUT'])
def add_scanned():
    user_id = request.args.get('user_id')

    scanned = {
        "_id" : request.args.get('beer_id'),
        "name" : request.args.get('beer_name')
    }

    if request.args.get('img_link'):
        scanned["img_link"] = request.args.get('img_link')

    current_app.logger.info("Adding beer scanned")

    collection.update_one({"_id":user_id}, { "$addToSet" : {"scanned" : scanned}}, upsert=True)

    return "Beer added to scanned"

【问题讨论】:

  • 编辑:为 curl 命令添加了 Flask 日志。
  • 还显示一个示例 curl 命令。随意用占位符替换敏感信息。
  • 添加 curl 命令示例。

标签: android curl flask retrofit2 gunicorn


【解决方案1】:

我正在编写一个 OkHttpRequest 调用来替换出现故障的 Retrofit 调用,结果遇到了this line

Android 不允许在主线程上进行网络调用,您只能在单独的线程或后台服务上进行同步调用。

阻止我拨打电话的原因是它是从另一个网络调用的主体发起的。使该问题难以追踪的是完全没有错误日志。我应该在哪里寻找对调试代码有用的提示?

我最终将代码更改为:

fun onScanFinished(barcode: Long) {
    uiScope.launch {
        BeerApi.retrofitService.searchByBarcode(barcode).enqueue(object : Callback<BeerES> {
            override fun onFailure(call: Call<BeerES>, t: Throwable) {
                Toast.makeText(getApplication(), "Failure: " + t.message, Toast.LENGTH_LONG)
                    .show()
            }
            override fun onResponse(call: Call<BeerES>, response: Response<BeerES>) {
                var beerScanned = response.body()
                if (beerScanned != null) {
                    UserApi.retrofitService.addScanned(
                        FirebaseAuth.getInstance().currentUser!!.uid,
                        beerScanned.beerId,
                        beerScanned.beerInfo.beerName
                    )
                }
            }
        })
    }
}

... 到这里(用自己的 uiScope 在另一个方法中提取第二个 Api 调用):

fun onScanFinished(barcode: Long) {
    uiScope.launch {
        BeerApi.retrofitService.searchByBarcode(barcode).enqueue(object : Callback<BeerES> {
            override fun onFailure(call: Call<BeerES>, t: Throwable) {
                Toast.makeText(getApplication(), "Failure: " + t.message, Toast.LENGTH_LONG)
                    .show()
            }
            override fun onResponse(call: Call<BeerES>, response: Response<BeerES>) {
                var beerScanned = response.body()
                if (beerScanned != null) {
                    addScanned(beerScanned)
                }
            }
        })
    }
}

private fun addScanned(beerScanned: BeerES) {
    uiScope.launch {
        UserApi.retrofitService.addScanned(
            FirebaseAuth.getInstance().currentUser!!.uid,
            beerScanned.beerId,
            beerScanned.beerInfo.beerName
        ).enqueue(object :  Callback<String> {
            override fun onFailure(call: Call<String>, t: Throwable) {
                 Toast.makeText(getApplication(), "Failure: " + t.message, Toast.LENGTH_LONG)
                    .show()
            }
            override fun onResponse(call: Call<String>, response: Response<String>) {
            }
        })
    }
}

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-09
    • 2021-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-29
    • 2012-04-22
    相关资源
    最近更新 更多