第一次改装后没有收到回应

Bir*_*der 7 java rest android flask retrofit

我在android上使用RetroFit以便将图像发送到REST服务器(使用Python和Flask开发)。该应用程序将第一张图像发送到存储该图像的服务器,并将该图像的ID返回给客户端。然后,客户端拍摄另一张照片并将其发送到服务器,这次是在端点URL中使用先前的图像ID。然后,服务器应计算从图像A到图像B的旋转并返回结果。客户端发送完第二张图像后,它应重复轮询端点以获取结果,直到服务器端计算完成。

第一个图像正确发送,服务器将其存储。客户端然后正确地从服务器接收响应。当客户端发送第二个图像时,会出现问题。服务器正确接收了POST,但是客户端似乎从未收到响应。第三条消息(轮询结果的GET请求)也是如此,服务器已接收到该消息,但客户端从未看到响应。

我的REST服务器的代码在这里

class Image(Resource):
    def post(self):
        file = request.files['uploaded_file']
        centerX = request.form['center_x']
        centerY = request.form['center_y']
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], str(id(True)) + ".jpg"))
            result = {'id' : id(), 'error' : True, 'result' : 5.5}
            return jsonify(result)
        else:
            return {'id' : -1, 'error' : False}

class Find_Transform(Resource):
    def post(self, first_id):
        result = {'id' : 1, 'error' : True, 'result' : 1.2}
        return jsonify(result)

class Find_Transform_Result(Resource):
    def get(self, first_id, second_id):
        print("Hello")
        result = {'id' : 0, 'error' : True, 'result' : 1.1}
        return jsonify(result)


api.add_resource(Image,'/image')
api.add_resource(Find_Transform,'/image/<first_id>/find-transform')
api.add_resource(Find_Transform_Result, '/image/<first_id>/find-transform/<second_id>')

if __name__ == '__main__':
    app.run(host='0.0.0.0',port='5002')
Run Code Online (Sandbox Code Playgroud)

如您所见,某些端点仍然只是用于测试REST API的存根。

我的Java Respond.class在这里

public class Respond {

    private int id;
    private Boolean error;
    private float result;

    public int getMessage() {
        return id;
    }


    public void setMessage(int id) {
        this.id = id;
    }

    public Boolean getError() {
        return error;
    }

    public void setError(Boolean error) {
        this.error = error;
    }

    public void setResult(float result) {
        System.out.println("Got Result");
        this.result = result;
    }

    public float getResult() {
        return result;
    }
}
Run Code Online (Sandbox Code Playgroud)

我的改装界面在这里

public interface FileApi {

    @Multipart
    @POST("/image")
    Call<Respond> uploadCropImage(@Part MultipartBody.Part file, @Part MultipartBody.Part x, @Part MultipartBody.Part y);

    @Multipart
    @POST("/image/{first_id}/find-transform")
    Call<Respond> uploadCompareImage(@Path("first_id") int id, @Part MultipartBody.Part file);

    @GET("/image/{first-id}/find-transform/{second-id}")
    Call<Respond> getCompareResult(@Path("first-id") int firstId, @Path("second-id") int secondId);
}
Run Code Online (Sandbox Code Playgroud)

使用两个单独的文件上传功能的原因是,第一个图像需要与用户选择的中心点一起发送,而第二个只是图像。

最后,我建立请求的部分在这里:

 private void uploadFirstImage(byte[] imageBytes) {

        FileApi service = RetroClient.getApiService();


        RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), imageBytes);

        MultipartBody.Part fileBody =
                MultipartBody.Part.createFormData("uploaded_file", "first_image.jpg", requestFile);


        RequestBody image_center_x = RequestBody.create(MediaType.parse("multipart/form-data"), Float.toString(points[0].x));
        MultipartBody.Part xBody = MultipartBody.Part.createFormData("center_x", null, image_center_x);

        RequestBody image_center_y = RequestBody.create(MediaType.parse("multipart/form-data"), Float.toString(points[0].y));
        MultipartBody.Part yBody = MultipartBody.Part.createFormData("center_y", null, image_center_y);


        Call<Respond> resultCall = service.uploadCropImage(fileBody, xBody, yBody);

        resultCall.enqueue(new Callback<Respond>() {
            @Override
            public void onResponse(Call<Respond> call, Response<Respond> response) {

                // Response Success or Fail
                if (response.isSuccessful()) {
                    if (response.body().getError()==true){
                        System.out.println(Double.toString(response.body().getResult()));
                        session_id = response.body().getMessage();
                    }


                } else {
                    Toast.makeText(getApplicationContext(),"Failed to communicate with server",Toast.LENGTH_LONG).show();
                }


            }

            @Override
            public void onFailure(Call<Respond> call, Throwable t) {
            }
        });
    }
Run Code Online (Sandbox Code Playgroud)

和这里:

private void uploadSecondImage(byte[] imageBytes) {

        FileApi service = RetroClient.getApiService();


        RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), imageBytes);

        MultipartBody.Part fileBody =
                MultipartBody.Part.createFormData("uploaded_file", "first_image.jpg", requestFile);


        Call<Respond> resultCall = service.uploadCompareImage(session_id,fileBody);

        resultCall.enqueue(new Callback<Respond>() {
            @Override
            public void onResponse(Call<Respond> call, Response<Respond> response) {

                // Response Success or Fail
                if (response.isSuccessful()) {
                    if (response.body().getError()==true){
                        System.out.println("Got Second Response");
                        resultID = response.body().getMessage();
                    }


                } else {
                    Toast.makeText(getApplicationContext(),"Failed to communicate with server",Toast.LENGTH_LONG).show();
                }


            }

            @Override
            public void onFailure(Call<Respond> call, Throwable t) {
                System.out.println("Failure");
            }
        });
    }
Run Code Online (Sandbox Code Playgroud)

最后,对于GET请求

    final boolean[] resultReady = {false};
    while (!resultReady[0]) {

        FileApi service = RetroClient.getApiService();
        Call<Respond> resultCall = service.getCompareResult(session_id, resultID);
        resultCall.enqueue(new Callback<Respond>() {
            @Override
            public void onResponse(Call<Respond> call, Response<Respond> response) {

                // Response Success or Fail
                if (response.isSuccessful()) {
                    if (response.body().getError()){
                        System.out.println("Got Response");
                        resultReady[0] = true;
                        theta[0] = response.body().getResult();
                        Toast.makeText(getApplicationContext(),"Measurement Recieved",Toast.LENGTH_LONG).show();
                    }
                    else {
                        Toast.makeText(getApplicationContext(),"Error Recieved",Toast.LENGTH_LONG).show();
                    }


                } else {
                    Toast.makeText(getApplicationContext(),"Failed to communicate with server",Toast.LENGTH_LONG).show();
                }


            }

            @Override
            public void onFailure(Call<Respond> call, Throwable t) {
            }
        });



    }
Run Code Online (Sandbox Code Playgroud)

我尝试将断点放在OnResponse函数中,并将调试语句放在OnResponse和OnFailure中,并且似乎该代码永远不会运行。这里可能出什么问题了?

编辑:好的,所以我有一些日志记录数据。我已经从python控制台测试了服务器

In [1]: import requests

In [2]: requests.get("http://localhost:5002/image/1/find-transform/2")
Out[2]: <Response [200]>

In [3]: _.text
Out[3]: '{"error": true, "id": 0, "result": 1.1}'

In [4]: requests.post("http://localhost:5002/image/find-transform")
Out[4]: <Response [404]>

In [5]: requests.post("http://localhost:5002/image/1/find-transform")
Out[5]: <Response [200]>

In [6]: _.text
Out[6]: '{"error": true, "id": 1, "result": 1.2}'
Run Code Online (Sandbox Code Playgroud)

我还根据注释的建议将http日志记录放在客户端,这给出了该日志记录的输出。

D/OkHttp: --> POST http://192.168.0.19:5002/image
    Content-Type: multipart/form-data; boundary=bc4ae771-2762-4124-8f07-d00dc925d886
D/OkHttp: Content-Length: 2044497
D/OkHttp: --bc4ae771-2762-4124-8f07-d00dc925d886
    Content-Disposition: form-data; name="uploaded_file"; filename="first_image.jpg"
    Content-Type: multipart/form-data
    Content-Length: 2043935
    (Truncated raw image data)
V/RenderScript: 0x7f77b4c000 Launching thread(s), CPUs 8
D/OkHttp: <-- 200 OK http://192.168.0.19:5002/image (410ms)
    Content-Type: application/json
    Content-Length: 39
    Server: Werkzeug/0.14.1 Python/3.6.8
    Date: Wed, 24 Jul 2019 17:00:47 GMT
D/OkHttp: {"error": true, "id": 9, "result": 5.5}
    <-- END HTTP (39-byte body)
I/System.out: 5.5
W/ImageReader_JNI: Unable to acquire a lockedBuffer, very likely client tries to lock more than maxImages buffers
I/System.out: Resultcall
D/OkHttp: --> POST http://192.168.0.19:5002/image/9/find-transform
    Content-Type: multipart/form-data; boundary=63de36cb-0961-4802-a97f-57b98ebcd8cb
D/OkHttp: Content-Length: 1655614
D/OkHttp: --63de36cb-0961-4802-a97f-57b98ebcd8cb
    Content-Disposition: form-data; name="uploaded_file"; filename="first_image.jpg"
    Content-Type: multipart/form-data
    Content-Length: 1655386
    (Truncated raw image data)
D/OkHttp: <-- HTTP FAILED: java.net.SocketException: sendto failed: EPIPE (Broken pipe)
D/OkHttp: --> GET http://192.168.0.19:5002/image/9/find-transform/-1
    --> END GET
D/OkHttp: <-- 200 OK http://192.168.0.19:5002/image/9/find-transform/-1 (90ms)
Run Code Online (Sandbox Code Playgroud)

看来服务器既正确地接收了请求,又发送了正确的响应。因此,客户端一定无法正确处理某些内容,但我不知道该怎么办。