【问题标题】:Retrofit - Calling REST services with POST method改造 - 使用 POST 方法调用 REST 服务
【发布时间】:2017-08-28 06:39:51
【问题描述】:

我第一次使用 Retrofit2 库通过 POST 方法调用 REST API 服务时遇到了困难。

我尝试通过 Prabeesh (youtube) 创建的教程来学习。但即使看起来我的API接口逻辑,ApiClient几乎相同,代码不起作用。

问题是教程是用 GET 方法显示的,我不太确定我对 POST 方法的类比解释是否正确..

使用网络浏览器(GET 方法)调用服务成功并创建用户。 API REST 客户端也显示此成功响应(POST 方法):

Content-Length: 56
Content-Type: text/html; charset=UTF-8
Date: Mon, 21 Aug 2017 08:18:51 GMT
Server: Apache/2.4.23 (Win64) PHP/5.6.25
X-Powered-By: PHP/5.6.25

对于使用 PHP 在 localhost 上创建的 REST 服务的此请求:

http://localhost/forman/forman/register/newUser/newSurname/geywh@test.com/password/CZE/2017-07-11/1/1/2017-07-12%2000:00:00.000000/2017-07-12%2000:00:00.000000

应该在后端服务调用 index.php 中的方法createUser

$app = new \Slim\App;

$app->post('/register/{first_name}/{sur_name}/{email}/{password} /{country}/{birthday}/{fav_driver}/{fav_team}/{created}/{last_login}', function (Request $request, Response $response) {
$first_name = $request->getAttribute('first_name');
$sur_name = $request->getAttribute('sur_name');
$email = $request->getAttribute('email');
$password = $request->getAttribute('password');
$country = $request->getAttribute('country');
$birthday = $request->getAttribute('birthday');
$fav_driver = $request->getAttribute('fav_driver');
$fav_team = $request->getAttribute('fav_team');
$created = $request->getAttribute('created');
$last_login = $request->getAttribute('last_login'); 

$db = new dbhandler();
$res = $db->createUser($first_name, $sur_name, $email, $password, $country, $birthday, $fav_driver, $fav_team, $created, $last_login);

        if ($res == USER_CREATED_SUCCESSFULLY) {
            $response->getBody()->write("Yep, user added!!!!, $first_name $sur_name");
        } else if ($res == USER_CREATE_FAILED) {
            $response->getBody()->write("Error!!!, $first_name $sur_name");
        } 

$response->getBody()->write("Hello, $first_name $sur_name");
return $response;
});
$app->run();
?>

因此,我使用 POST 方法调用 .htaccess 中定义的 /register 站点构建了 API 接口:

public interface ApiInterface {
@POST("/register")
Call<User> createUser(@Body User user);}

我还在使用带有构造函数、getter、setter 和序列化到 REST 服务上的字段的 User 类..

public class User {
//Constructor
public User(String first_name, String sur_name, String email, String password, String country, String birthday, int fav_driver, int fav_team, String created, String last_login) {
}
@SerializedName("first_name")
public String first_name;
@SerializedName("sur_name")
public String sur_name;
@SerializedName("email")
public String email;
@SerializedName("password")
public String password;
@SerializedName("country")
public String country;
@SerializedName("birthday")
public String birthday;
@SerializedName("fav_driver")
public Integer fav_driver;
@SerializedName("fav_team")
public Integer fav_team;
@SerializedName("created")
public String created;
@SerializedName("last_login")
public String last_login;

// Setters
public void setFirst_name(String first_name) {
    this.first_name = first_name;
}
public void setSur_name(String sur_name) {
    this.sur_name = sur_name;
}
public void setEmail(String email) {
    this.email = email;
}
public void setPassword(String password) {
    this.password = password;
}
public void setCountry(String country) {
    this.country = country;
}
public void setBirthday(String birthday) {
    this.birthday = birthday;
}
public void setFav_driver(Integer fav_driver) {
    this.fav_driver = fav_driver;
}
public void setFav_team(Integer fav_team) {
    this.fav_team = fav_team;
}
public void setCreated(String created) {
    this.created = created;
}
public void setLast_login(String last_login) {
    this.last_login = last_login;
}

// Getters
public String getFirst_name() {
    return first_name;
}
public String getSur_name() {
    return sur_name;
}
public String getEmail() {
    return email;
}
public String getPassword() {
    return password;
}
public String getCountry() {
    return country;
}
public String getBirthday() {
    return birthday;
}
public Integer getFav_driver() {
    return fav_driver;
}
public Integer getFav_team() {
    return fav_team;
}
public String getCreated() {
    return created;
}
public String getLast_login() {
    return last_login;
}
}

Api Client 创建改造实例:

public class ApiClient {
public static final String BASE_URL = "http://localhost/forman/forman/";
public static Retrofit retrofit = null;

public static Retrofit getApiClient()  {

    if(retrofit==null) {

        retrofit = new Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create()).build();

    }
    return retrofit;
}
}

并在我的代码中的 onClick 方法期间调用 API 接口和 API 客户端:

public void addButtonClickListener() {
    final Context context = this;

    Button confirm = (Button) findViewById(R.id.bt_save_reg);
    confirm.setOnClickListener(new OnClickListener() {

        public void onClick(View v) {



            TextView firstname = (TextView) findViewById(R.id.editText2);
            String first_name = (String) firstname.getText().toString();

            TextView surname = (TextView) findViewById(R.id.editText3);
            String sur_name = (String) surname.getText().toString();

            TextView email = (TextView) findViewById(R.id.reg_et_email);
            String e_mail = (String) email.getText().toString();

            TextView password = (TextView) findViewById(R.id.etPassword);
            String pass = (String) email.getText().toString();

            TextView country_reg = (TextView) findViewById(R.id.reg_tv_country);
            String country = (String) country_reg.getText().toString();

            TextView birthday_reg = (TextView) findViewById(R.id.birthday_reg);
            String birthday = (String) birthday_reg.getText().toString();

//                TextView fav_driver = (TextView) findViewById(R.id.textView4);
//                Integer favdriver = Integer.valueOf((String) fav_driver.getText().toString());
//
//                TextView fav_team = (TextView) findViewById(R.id.TextViewFavTeam);
//                Integer favteam = Integer.valueOf((String) fav_team.getText().toString());

            User user = new User(first_name, sur_name, e_mail, pass, country, birthday, 1, 1, "2017-07-12 00:00:00.000000", "2017-07-12 00:00:00.000000");

            final ApiInterface apiInterface;

            apiInterface = ApiClient.getApiClient().create(ApiInterface.class);

            Call<User> call = apiInterface.createUser(user);

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

                    Log.d("CREATION", "Check this, because this and    OnFailure never happened!");

                }

                @Override
                public void onFailure(Call<User> call, Throwable throwable) {

                }
            });


        }

    });

}

抱歉,对于大量代码,我是 Android、Java、Retrofit 的新手。所以,目前我对代码的任何部分都不太确定。我真的很感谢你的帮助,否则我很快就会把子弹放在我的脑海里:)

下一次,我将学习只有几个领域的简单模型..

感谢大家检查我的问题,

祝你有美好的一天, 吉日

【问题讨论】:

    标签: android retrofit


    【解决方案1】:

    尝试删除改造注释中的斜线。您的基本网址最后已经有斜线。结果,您尝试将数据发送到

    http://localhost/forman/forman//register
    

    当前代码

    @POST("/register")
    

    新代码

    @POST("register")
    

    【讨论】:

    • 改进完成,但仍然无法正常工作。与之前相同的行为 - 这意味着 call.enqueue 没有得到响应。回调 - onResponse 和 onFailure 只是跳过,而不是触发。
    【解决方案2】:

    由于我仍然卡住了,我最小化了我的代码(通过创建 API 测试项目)并只提取了代码中最重要的部分,以避免一些误解并让你更容易,因为我还不清楚..

    我在 onCreate 活动中调用enqueue 方法作为异步请求,以避免手动创建后台线程..

        protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
    
        User user = new User("John", "Markovicz", "john-markovicz@email.com", "password", "UK", "2017-07-11", 1, 1, "2017-07-12 00:00:00.000000", "2017-07-12 00:00:00.000000" );
    
        APIInterface apiinterface = APIclient.getClient().create(APIInterface.class);
        Call<User> call = apiinterface.createUser(user);
    
        call.enqueue(new Callback<User>() {
            @Override
            public void onResponse(Call<User> call, Response<User> response) {
                User result = response.body();
            }
    
            @Override
            public void onFailure(Call<User> call, Throwable throwable) {
            }
        });
    }
    

    如您所见,我想将用户保存在后端数据库中。用户的实例是使用 User 类中定义的构造函数创建的(我希望不需要 setter 和 getter?):

    public class User {
    public User(String first_name, String sur_name, String email, String password, String country, String birthday, Integer fav_driver, Integer fav_team, String created, String last_login) {
    }
    }
    

    我用于将数据设置到后端的这个接口和这个 Retrofit 实例:

    public interface APIInterface {
    
    @POST("register")
    Call<User> createUser(@Body User user);
    }
    

    改造实例:

    public class APIclient {
    
    public static Retrofit getClient() {
    
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("http://localhost/forman/forman/")
                .addConverterFactory(GsonConverterFactory.create()).build();
        return retrofit;
    }
    }
    

    没有显示错误。我在 Android SDK 的设置上也遇到了一些问题,但是在里面安装了 API 26 之后,我在 logcat 中没有收到任何错误。 我通过高级 REST 客户端测试了一次 agin POST 方法,并且此有效负载请求已正确处理并存储在 DB 中:

    地点:

    http: //localhost/forman/forman/register
    Content-Type: application/x-www-form-urlencoded
    

    有效载荷:

    first_name=First_name&sur_name=Sur_name&email=Test@gmail.com&password=password&country=CZE&birthday=2017-07-11&fav_driver=1&fav_team=1&created=2017-07-12 00:00:00.000000&last_login=2017-07-12 00:00:00.000000
    

    有人有经验验证我的简单代码吗?

    谢谢你, 吉日

    【讨论】:

    • 你能说得更具体点吗?您已发送发布请求。什么是服务器响应?什么http代码?您是否捕获了服务器日志?此外,您应该为您的请求设置标题:Accept 和 Content-Type
    • 很奇怪,这个 POST 请求似乎根本没有在 access.log 中登录服务器。我明天将继续检查这个并设置标题..谢谢
    • 我建议使用 Wireshark 来捕获数据包,看看你实际发送到服务器的是什么
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-01
    相关资源
    最近更新 更多