如何正确管理 Retrofit POST 请求?
How to properly manage a Retrofit POST request?
实际上我正在尝试 post 一个文本文件到我的服务器,当我发送文件时我可以处理错误但我没有收到响应(如果文件已发送,网络出现故障,因此服务器收到了文件,但设备不知道)
因为现在我遇到了一个问题,因为如果我在设备 return 在线时没有收到响应,它会再次发送相同的文件,我会阻止它。
似乎是在连接失败或类似情况下隐藏地重试发送文件。
这是我使用 onClick 发送文件的方法:
public void sendPost() {
@SuppressLint({"SdCardPath", "DefaultLocale"}) final File file = new File("/data/data/com.example.igardini.visualposmobile/files/"+String.format("%03d", Integer.valueOf(nTerminalino))+"_"+nTavoli.getText().toString()+".txt");
final MultipartBody.Builder builder = new MultipartBody.Builder();
builder.setType(MultipartBody.FORM);
final RequestBody fbody = RequestBody.create(MediaType.parse("text/*"), file);
builder.addFormDataPart(String.format("%03d", Integer.valueOf(nTerminalino))+"_"+nTavoli.getText().toString(), file.getName(),fbody);
final MultipartBody requestBody = builder.build();
final APIService apiService = ApiUtils.getAPIService(ipCASSA);
final Call<Void> calls = apiService.savePost(requestBody);
calls.enqueue(new Callback<Void>() {
@Override
public void onResponse(@NonNull Call<Void> call, @NonNull Response<Void> response) {
if (response.isSuccessful()) {
Log.i("RESPONSE: ", response.toString());
Print();
dialogLoading.dismiss();
Runtime.getRuntime().gc();
// checkFile task = new checkFile();
// task.execute();
}else {
Toast.makeText(pterm.this,"ERRORE",Toast.LENGTH_LONG).show();
}
}
@Override
public void onFailure(@NonNull Call<Void> call, @NonNull Throwable t) {
if(t instanceof IOException) {
Log.e("TAG", t.toString());
MediaPlayer mpFound = MediaPlayer.create(pterm.this, R.raw.errorsound);
mpFound.start();
Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
if (v.hasVibrator()) {
v.vibrate(6000);
}
new GlideToast.makeToast(pterm.this, "CONNESSIONE FALLITA!", GlideToast.LENGTHLONG, GlideToast.FAILTOAST).show();
dialogLoading.dismiss();
}
}
});
}
虽然这是我的其他有用的 类:
class ApiUtils {
private ApiUtils() {}
static APIService getAPIService(String ipCASSA) {
String BASE_URL = "http://"+ipCASSA+"/web/";
final OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(10000, TimeUnit.MILLISECONDS)
.writeTimeout(10000, TimeUnit.MILLISECONDS)
.readTimeout(10000, TimeUnit.MILLISECONDS)
.retryOnConnectionFailure(false)
.build();
return RetrofitClient.getClient(BASE_URL,okHttpClient).create(APIService.class);
}
}
public interface APIService {
@POST("CART=PTERM")
Call<Void> savePost(@Body RequestBody text);
}
class RetrofitClient {
private static Retrofit retrofit = null;
static Retrofit getClient(String baseUrl, OkHttpClient okHttpClient) {
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
在这种情况下,我会将某种设备生成的随机 ID 添加到文件中,并将其与请求一起发送。
在服务器端,我会更改逻辑,首先尝试使用此 ID 在数据库中定位文件,如果存在 none,则存储它并且 return 状态正常,可能还有服务器端 ID (以后可能会派上用场)。
如果有根据请求提供 ID 的文件,只需 return 状态为 200 的服务器端 ID - 这样您就不会存储它两次。
你甚至可以走得更远——如果你没有稳定的连接(从描述来看似乎是这样)你甚至可以进行单独的 REST 调用以通过生成的 ID 或校验和检查文件是否在服务器端,如果不是则开始发送它 - 它会安全 bandwitch。
不必生成 ID - 例如,它可以是文件的校验和。任何对你来说更容易的事。
要生成 ID,您可以使用 Android 的 UUID
https://developer.android.com/reference/java/util/UUID
校验和检查这个答案:
How to generate an MD5 checksum for a file in Android?
顺便说一句 - 我不会做 10 秒的超时限制 - 它太多了,用户体验会很糟糕
实际上我正在尝试 post 一个文本文件到我的服务器,当我发送文件时我可以处理错误但我没有收到响应(如果文件已发送,网络出现故障,因此服务器收到了文件,但设备不知道)
因为现在我遇到了一个问题,因为如果我在设备 return 在线时没有收到响应,它会再次发送相同的文件,我会阻止它。
似乎是在连接失败或类似情况下隐藏地重试发送文件。
这是我使用 onClick 发送文件的方法:
public void sendPost() {
@SuppressLint({"SdCardPath", "DefaultLocale"}) final File file = new File("/data/data/com.example.igardini.visualposmobile/files/"+String.format("%03d", Integer.valueOf(nTerminalino))+"_"+nTavoli.getText().toString()+".txt");
final MultipartBody.Builder builder = new MultipartBody.Builder();
builder.setType(MultipartBody.FORM);
final RequestBody fbody = RequestBody.create(MediaType.parse("text/*"), file);
builder.addFormDataPart(String.format("%03d", Integer.valueOf(nTerminalino))+"_"+nTavoli.getText().toString(), file.getName(),fbody);
final MultipartBody requestBody = builder.build();
final APIService apiService = ApiUtils.getAPIService(ipCASSA);
final Call<Void> calls = apiService.savePost(requestBody);
calls.enqueue(new Callback<Void>() {
@Override
public void onResponse(@NonNull Call<Void> call, @NonNull Response<Void> response) {
if (response.isSuccessful()) {
Log.i("RESPONSE: ", response.toString());
Print();
dialogLoading.dismiss();
Runtime.getRuntime().gc();
// checkFile task = new checkFile();
// task.execute();
}else {
Toast.makeText(pterm.this,"ERRORE",Toast.LENGTH_LONG).show();
}
}
@Override
public void onFailure(@NonNull Call<Void> call, @NonNull Throwable t) {
if(t instanceof IOException) {
Log.e("TAG", t.toString());
MediaPlayer mpFound = MediaPlayer.create(pterm.this, R.raw.errorsound);
mpFound.start();
Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
if (v.hasVibrator()) {
v.vibrate(6000);
}
new GlideToast.makeToast(pterm.this, "CONNESSIONE FALLITA!", GlideToast.LENGTHLONG, GlideToast.FAILTOAST).show();
dialogLoading.dismiss();
}
}
});
}
虽然这是我的其他有用的 类:
class ApiUtils {
private ApiUtils() {}
static APIService getAPIService(String ipCASSA) {
String BASE_URL = "http://"+ipCASSA+"/web/";
final OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(10000, TimeUnit.MILLISECONDS)
.writeTimeout(10000, TimeUnit.MILLISECONDS)
.readTimeout(10000, TimeUnit.MILLISECONDS)
.retryOnConnectionFailure(false)
.build();
return RetrofitClient.getClient(BASE_URL,okHttpClient).create(APIService.class);
}
}
public interface APIService {
@POST("CART=PTERM")
Call<Void> savePost(@Body RequestBody text);
}
class RetrofitClient {
private static Retrofit retrofit = null;
static Retrofit getClient(String baseUrl, OkHttpClient okHttpClient) {
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
在这种情况下,我会将某种设备生成的随机 ID 添加到文件中,并将其与请求一起发送。
在服务器端,我会更改逻辑,首先尝试使用此 ID 在数据库中定位文件,如果存在 none,则存储它并且 return 状态正常,可能还有服务器端 ID (以后可能会派上用场)。
如果有根据请求提供 ID 的文件,只需 return 状态为 200 的服务器端 ID - 这样您就不会存储它两次。
你甚至可以走得更远——如果你没有稳定的连接(从描述来看似乎是这样)你甚至可以进行单独的 REST 调用以通过生成的 ID 或校验和检查文件是否在服务器端,如果不是则开始发送它 - 它会安全 bandwitch。
不必生成 ID - 例如,它可以是文件的校验和。任何对你来说更容易的事。
要生成 ID,您可以使用 Android 的 UUID https://developer.android.com/reference/java/util/UUID
校验和检查这个答案: How to generate an MD5 checksum for a file in Android?
顺便说一句 - 我不会做 10 秒的超时限制 - 它太多了,用户体验会很糟糕