Android端通过REST API向Frappe上传文件遇内部服务器错误求助
问题:Android通过URI上传文件到Frappe REST API报INTERNAL SERVER ERROR
通过URL调用Frappe的REST API上传文件正常,但从Android设备用URI上传时触发INTERNAL SERVER ERROR,相关代码和日志如下:
Android端相关代码
AsyncTask中调用上传逻辑
//Call upload function from async task @Override protected String doInBackground(String... strings) { if (strings[0] != null) { try { file1 = new File(strings[0]); RequestBody requestFile = RequestBody.create( MediaType.parse(getContentResolver().getType(uri)), file1 ); // MultipartBody.Part is used to send also the actual file name MultipartBody.Part body = MultipartBody.Part.createFormData("file_url", file1.getName(), requestFile); uploadFile(body); } catch (Exception e) { e.printStackTrace(); } } else { try { file2 = new File(strings[1]); // create RequestBody instance from file RequestBody requestFile = RequestBody.create( MediaType.parse(getContentResolver().getType(uri)), file2 ); // MultipartBody.Part is used to send also the actual file name MultipartBody.Part body = MultipartBody.Part.createFormData("file_url", file2.getName(), requestFile); uploadFile(body); } catch (Exception e) { e.printStackTrace(); } } return null; }
Retrofit上传方法
//Retrofit Call private void uploadFile(MultipartBody.Part body){ Log.v("HitMan",body.toString()); String doctypeString = "Lead"; String docnameString = name; RequestBody doctype = RequestBody.create( okhttp3.MultipartBody.FORM, doctypeString); RequestBody docname = RequestBody.create( okhttp3.MultipartBody.FORM, docnameString); Log.v("Body",body.toString()); Log.v("Doctype",doctype.toString()); Log.v("Docname",docname.toString()); UserService uploadService = retrofit.create(UserService.class); Call<ResponseBody> call4 = uploadService.uploadFile(body,doctype,docname); call4.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { if(response.isSuccessful()) { progressBar.setVisibility(View.GONE); Toast.makeText(LeadDetailActivity.this,"Uploaded Successfully",Toast.LENGTH_SHORT).show(); } else{ progressBar.setVisibility(View.GONE); Log.v("Custom Error :",response.message()); Toast.makeText(LeadDetailActivity.this,"Process Failed!",Toast.LENGTH_SHORT).show(); } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { progressBar.setVisibility(View.GONE); Log.v("Create Response Error", t.toString()); } }); }
Retrofit接口定义
//Interface @Multipart @POST("api/method/upload_file") Call<ResponseBody> uploadFile(@Part MultipartBody.Part file_url,@Part("doctype") RequestBody doctype,@Part("docname") RequestBody docname);
错误日志
V/URI: content://com.mi.android.globalFileexplorer.myprovider/external_files/temp.jpg D/File Path :: /storage/emulated/0/temp.jpg V/FA: Activity resumed, time: 5674872 V/FA: Connecting to remote service D/FA: Connected to remote service V/FA: Processing queued up service tasks: 1 V/HitMan: okhttp3.MultipartBody$Part@7a76c54 V/Body: okhttp3.MultipartBody$Part@7a76c54 V/Doctype: okhttp3.RequestBody$2@242e7fd V/Docname: okhttp3.RequestBody$2@3da0cf2 V/Custom Error :: INTERNAL SERVER ERROR
排查方向与解决方案
1. 修正文件参数名
Frappe的upload_file接口中,本地文件上传的表单字段名是file,而file_url是用来上传网络文件地址的参数。你当前代码里用了错误的字段名,导致服务端无法识别上传的文件:
- 将
MultipartBody.Part.createFormData("file_url", ...)改为MultipartBody.Part.createFormData("file", ...) - 同时把接口定义中的
@Part MultipartBody.Part file_url改为@Part MultipartBody.Part file
2. 解决Content URI的权限与读取问题
直接将content://开头的URI转成File对象存在权限风险,部分设备的文件管理器会限制APP直接读取对应路径。应该通过ContentResolver读取文件流来创建RequestBody:
// 替换原有的File转RequestBody逻辑 InputStream inputStream = getContentResolver().openInputStream(uri); byte[] fileBytes = IOUtils.toByteArray(inputStream); // 可引入org.apache.commons.io.IOUtils,或自行实现流转字节数组 RequestBody requestFile = RequestBody.create( MediaType.parse(getContentResolver().getType(uri)) != null ? MediaType.parse(getContentResolver().getType(uri)) : MediaType.parse("application/octet-stream"), fileBytes );
3. 检查Frappe服务端日志
INTERNAL SERVER ERROR的具体原因需要看服务端日志,登录Frappe后台,查看Logs模块中的错误堆栈,能直接定位服务端解析失败的具体原因(比如参数缺失、文件格式不支持等)。
4. 确认MediaType正确性
如果getContentResolver().getType(uri)返回null,手动指定对应文件的MediaType(比如图片用image/jpeg、image/png),避免服务端因无法识别文件类型报错。
内容的提问来源于stack exchange,提问作者Ryan1
相关产品推荐
相关产品推荐

