You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Retrofit报错java.lang.IllegalArgumentException:API声明需为接口的解决问询

问题排查:Retrofit 报错 "API declarations must be interfaces"

错误信息

java.lang.IllegalArgumentException: API declarations must be interfaces.

相关代码

Activity 音频上传代码

private void uploadAudio() {

    Long date = new Date().getTime();

    Date current_time = new Date(Long.valueOf(date));
    String file_path = getApplicationContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).getPath() + "/" + current_time + ".3gp";


    File audioFile = new File(file_path);
    RequestBody requestFile = RequestBody.create(MediaType.parse("audio/*"), audioFile);
    MultipartBody.Part audioPart = MultipartBody.Part.createFormData("audio", audioFile.getName(), requestFile);

    ApiService apiService = ApiClient.getClient().create(ApiService.class);
    Call<ResponseBody> call = apiService.uploadAudio(audioPart);
    call.enqueue(new retrofit2.Callback<ResponseBody>() {
        @Override
        public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> response) {
            if (response.isSuccessful()){
                if (response.body().toString().equals("200")){
                    Toast.makeText(getApplicationContext(), "Audio uploaded Successfully", Toast.LENGTH_SHORT).show();
                }else {
                    Toast.makeText(getApplicationContext(),"Audio Upload Failed", Toast.LENGTH_SHORT).show();
                }
            }

        }

        @Override
        public void onFailure(Call<ResponseBody> call, Throwable t) {
            Toast.makeText(getApplicationContext(), t.toString(), Toast.LENGTH_SHORT).show();

        }
    });
}

ApiService 原代码

public class ApiService {
    @Multipart
    @POST("retroapi2.php")
    Call<ResponseBody> uploadAudio(@Part MultipartBody.Part audio) {

        return null;
    }
}

ApiClient 代码

public class ApiClient {
    private static final String BASE_URL = "http://mysite.in/atmedia/ud/";

    private static Retrofit retrofit;

    public static Retrofit getClient() {
        if (retrofit == null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }
        return retrofit;
    }
}

后端PHP代码

if($_SERVER['REQUEST_METHOD']=='POST'){

 //Getting post data 

 $fileName  =  $_FILES['audio']['name'];

$tempPath  =  $_FILES['audio']['tmp_name'];

$fileSize  =  $_FILES['audio']['size'];

$upload_path = 'upload/'; // set upload folder path 

require_once('retconfig.php');
  
 //Creating an SQL Query to insert into database 
 //Here you may need to change the retrofit_users because it is the table I created
 //if you have a different table write your table's name
 
 //This query is to check whether the username or email is already registered or not 
 $sql = "SELECT * FROM demo WHERE mobile='$mobile'";
 
 //If variable check has some value from mysqli fetch array 
 //That means username or email already exist 
 $check = mysqli_fetch_array(mysqli_query($con,$sql));
 
 //Checking check has some values or not 
 if(isset($check)){
 //If check has some value that means username already exist 
 echo 'username or email already exist';
 }else{ 
 //If username is not already exist 
 //Creating insert query 
       
if($fileSize < 5000000){
    move_uploaded_file($tempPath, $upload_path . $fileName); // move file from system temporary path to our upload folder path 
}

问题原因

Retrofit 框架要求所有API声明必须是接口(interface),不能是普通类(class)。你当前的ApiService用class定义,违反了这个核心规范,因此触发该异常。

解决方案

将ApiService修改为接口,移除方法的具体实现:

public interface ApiService {
    @Multipart
    @POST("retroapi2.php")
    Call<ResponseBody> uploadAudio(@Part MultipartBody.Part audio);
}

额外优化建议

  1. 文件路径优化:直接用Date对象拼接文件名会生成带空格的路径,建议改用时间戳字符串:
    String file_path = getApplicationContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).getPath() + "/" + date + ".3gp";
    
  2. ResponseBody 正确读取:response.body().toString()无法获取真实返回内容,需读取流数据:
    if (response.isSuccessful()) {
        try {
            String responseStr = response.body().string();
            if ("200".equals(responseStr)) {
                Toast.makeText(getApplicationContext(), "Audio uploaded Successfully", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(getApplicationContext(),"Audio Upload Failed", Toast.LENGTH_SHORT).show();
            }
        } catch (IOException e) {
            e.printStackTrace();
            Toast.makeText(getApplicationContext(), "Failed to read response", Toast.LENGTH_SHORT).show();
        }
    }
    
  3. 后端代码完善:当前存在SQL注入风险,建议用预处理语句;同时需补充上传结果的响应输出:
    if($fileSize < 5000000){
        if(move_uploaded_file($tempPath, $upload_path . $fileName)){
            echo "200"; // 上传成功返回标识
        } else {
            echo "Upload failed";
        }
    } else {
        echo "File too large";
    }
    

内容的提问来源于stack exchange,提问作者kranthi chevuri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 17:47:00