如何使用 Parse REST API 和 Retrofit 将文件发送到 Parse 服务器?

Mon*_*bao 5 android parse-platform retrofit2

我已经构建了一个 Retrofit 构建器,以便我可以使用 Retrofit 将文件发送到 Parse 数据库

public static Retrofit buildParseUpload() {
        Retrofit.Builder retrofitBuilder = new Retrofit.Builder()
                .baseUrl({contains server running Parse})
                .addConverterFactory(GsonConverterFactory.create())
                .client(authenticate());
        return retrofitBuilder.build();
}
Run Code Online (Sandbox Code Playgroud)

这是authenticate()

private static OkHttpClient authenticateParse() {
        OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
        httpClient.addInterceptor(new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request request = chain.request();
                Request.Builder requestBuilder = request.newBuilder()
                        .header("X-Parse-Application-Id", APPLICATION_ID)
                        .header("X-Parse-REST-API-Key", MASTER_KEY)
                        .method(request.method(), request.body());
                Request newRequest = requestBuilder.build();
                return chain.proceed(newRequest);
            }
        });
        OkHttpClient client = httpClient.build();
        return client;
    }
Run Code Online (Sandbox Code Playgroud)

这是ParseService

public interface ParseService {
    @Multipart
    @POST("classes/" + Parameter.Classes.TABLE_NAME + "/")
    Call<Void> uploadFile(@PartMap Map<String, Object> map);
}
Run Code Online (Sandbox Code Playgroud)

这是Call实例:

private void saveFileToParse(File answerFile) {
        //TODO: Save file manually Parse
        String filePath = "";
        Retrofit retrofit = RetrofitBuilder.buildParseUpload();
        ParseService parseService = retrofit.create(ParseService.class);
        Call<Void> call = parseService.uploadFile(getPartMap(answerFile));
        call.enqueue(new Callback<Void>() {
            @Override
            public void onResponse(Call<Void> call, Response<Void> response) {
                if (response.code() == 200) {
                    Log.d(TAG, "response: " + response.body().toString());
                } else {
                    Log.d(TAG, "response: " + response.code());
                    Log.d(TAG, "response: " + response.message());
                }
            }

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

    private Map<String, Object> getPartMap(File file) {
        Map<String, Object> map = new HashMap<>();
        map.put("file", file);
        return map;
    }
Run Code Online (Sandbox Code Playgroud)

改造版本: com.squareup.retrofit2:retrofit:2.1.0

结果:HTTP 400:错误请求

日志:

  D/OkHttp: --> POST http://parse.ip.address.xx:port/parse/2.2.16/classes/classes_of_files/ http/1.1
  D/OkHttp: Content-Type: multipart/form-data; boundary=2b7a3c4d-8e13-4baa-b99f-2148560eafef
  D/OkHttp: Content-Length: 308
  D/OkHttp: X-Parse-Application-Id: —————
  D/OkHttp: X-Parse-REST-API-Key: ———————
  D/OkHttp: --> END POST
  D/OkHttp: --> POST http://parse.ip.address.xx:port/parse/2.2.16/classes/classes_of_files/ http/1.1
  D/OkHttp: Content-Type: multipart/form-data; boundary=220df264-d21b-4ddd-b0d4-df13e2b4193e
  D/OkHttp: Content-Length: 305
  D/OkHttp: X-Parse-Application-Id: ——————
  D/OkHttp: X-Parse-REST-API-Key: —————
  D/OkHttp: --> END POST
E/Auth: [GoogleAccountDataServiceImpl] getToken() -> BAD_AUTHENTICATION. Account: <ELLIDED:-1341404215>, App: com.android.vending, Service: androidsecure
                                       elc: Long live credential not available.
                                           at eld.a(SourceFile:3099)
                                           at ejq.a(SourceFile:397)
                                           at ejp.a(SourceFile:31369)
                                           at ejp.a(SourceFile:313)
                                           at fla.a(SourceFile:1201)
                                           at fkz.a(SourceFile:530)
                                           at fkz.a(SourceFile:196)
                                           at egp.a(SourceFile:284)
                                           at egp.a(SourceFile:204)
                                           at egu.a(SourceFile:1510)
                                           at egt.a(SourceFile:920)
                                           at egt.e(SourceFile:534)
                                           at egs.a(SourceFile:37)
                                           at ehv.getAuthToken(SourceFile:179)
                                           at android.accounts.AbstractAccountAuthenticator$Transport.getAuthToken(AbstractAccountAuthenticator.java:214)
                                           at android.accounts.IAccountAuthenticator$Stub.onTransact(IAccountAuthenticator.java:113)
                                           at android.os.Binder.execTransact(Binder.java:453)
01-27 04:21:03.983 8965-1170/? W/GLSActivity: ehh: BadAuthentication
                                                  at egu.a(SourceFile:1526)
                                                  at egt.a(SourceFile:920)
                                                  at egt.e(SourceFile:534)
                                                  at egs.a(SourceFile:37)
                                                  at ehv.getAuthToken(SourceFile:179)
                                                  at android.accounts.AbstractAccountAuthenticator$Transport.getAuthToken(AbstractAccountAuthenticator.java:214)
                                                  at android.accounts.IAccountAuthenticator$Stub.onTransact(IAccountAuthenticator.java:113)
                                                  at android.os.Binder.execTransact(Binder.java:453)
  D/OkHttp: <-- 400 Bad Request http://52.220.38.201:1337/parse/2.2.16/classes/survey_usage_files/ (185ms)
  D/OkHttp: X-Powered-By: Express
  D/OkHttp: Access-Control-Allow-Origin: *
  D/OkHttp: Access-Control-Allow-Methods: GET,PUT,POST,DELETE,OPTIONS
  D/OkHttp: Access-Control-Allow-Headers: X-Parse-Master-Key, X-Parse-REST-API-Key, X-Parse-Javascript-Key, X-Parse-Application-Id, X-Parse-Client-Version, X-Parse-Session-Token, X-Requested-With, X-Parse-Revocable-Session, Content-Type
  D/OkHttp: Content-Type: application/json; charset=utf-8
  D/OkHttp: Content-Length: 30
  D/OkHttp: Date: Fri, 20 Jan 2017 09:22:36 GMT
  D/OkHttp: Connection: keep-alive
  D/OkHttp: <-- END HTTP
  D/OkHttp: <-- 400 Bad Request http://parse.ip.address.xx:port/parse/2.2.16/classes/classes_of_files/ (183ms)
  D/OkHttp: X-Powered-By: Express
  D/OkHttp: Access-Control-Allow-Origin: *
  D/OkHttp: Access-Control-Allow-Methods: GET,PUT,POST,DELETE,OPTIONS
  D/OkHttp: Access-Control-Allow-Headers: X-Parse-Master-Key, X-Parse-REST-API-Key, X-Parse-Javascript-Key, X-Parse-Application-Id, X-Parse-Client-Version, X-Parse-Session-Token, X-Requested-With, X-Parse-Revocable-Session, Content-Type
  D/OkHttp: Content-Type: application/json; charset=utf-8
  D/OkHttp: Content-Length: 30
  D/OkHttp: Date: Fri, 20 Jan 2017 09:22:36 GMT
  D/OkHttp: Connection: keep-alive
  D/OkHttp: <-- END HTTP
Run Code Online (Sandbox Code Playgroud)

为什么我不使用 Parse Android SDK?

我们确定我们需要使用 Parse REST API 来解决这个问题,而不是 Parse Android SDK,因为我们在上传文件时遇到了 Parse Android SDK 的问题,尤其是在使用它的回调时。

另请注意,基本 URL 不是api.parse.com,而是我们运行 Parse 的另一个远程服务器。

非常感谢您的回答!