在进行收藏操作时,一般都会使用post方式将收藏信息提交到后台服务器,那么在网站中,是不能用输入网址的形式获取数据的,所以提供了一个工具Postman《Postman下载地址》
Postman的使用很简单,输入要请求的网址,加上要请求的参数,它会自动拼接成一条post请求。
然后发送请求,就会得到服务器的响应。
所以在收藏时,如果想知道服务器返回的数据是什么样的,就可以使用Postman。
1、收藏
其实收藏很简单,只需要根据文章的id,来将收藏请求post到服务器,服务器会将信息保存,用户可以查看保存信息。
我在此设计的是,长按文章Item,就会收藏该文章。
//长按收藏
lv_main.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
int item = position - headCount;
int aid = list.get(item).getId();
//收藏
fPresenter.getCollection(aid);
return false;
}
});
在解析服务器返回的数据时,会做一系列的判断
@Override
public void showCollection(CollectBean collectBean) {
Log.e("TAG","coll==="+collectBean);
if(collectBean.getErrorCode() == 0 && collectBean.getErrorMsg().equals("")){
Toast.makeText(getContext(),"收藏成功",Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(getContext(),collectBean.getErrorMsg(),Toast.LENGTH_SHORT).show();
}
}
在测试的时候,并没有收藏成功,而是出现了错误信息。
data=null, errorCode=-1001, errorMsg='请先登录!'
之前明明已经登录了,为什么还是要我登录?原来只是你自己根据信息解析出来的数据,判断服务器返回的信息是否符合要求,而自行进入到了主界面,但是系统和服务器并没有认为你已经登录了,如下代码(登录代码):
if(loginBean.getErrorCode() == 0 && loginBean.getErrorMsg().equals("")){
//登录成功
Intent intent = new Intent();
intent.putExtra("username",username);
intent.setClass(LoginActivity.this,MainActivity.class);
startActivity(intent);
//保存登录信息
SPUtils.getInstance().saveInfo("login",true);
finish();
}else{
Toast.makeText(this,loginBean.getErrorMsg(),Toast.LENGTH_SHORT).show();
}
要如何解决这个问题,那么就引进了Cookie。
2、Cookie
Cookie可以理解为一段保存在客户端的字符串,就拿登录这个例子来说,我们第一次登录的时候,会通过用户名和密码来登录,去向服务器发起请求,这个时候,服务器接收到了登录请求之后,会判断用户是否符合注册信息,如果符合注册信息,那么就会将登录成功的信息 + Cookie一起发送到客户端,客户端需要将Cookie持久保存在客户端,等到下一次请求时,我们不需要使用用户名和密码登录,只需要使用Cookie,去验证服务器,这也有效地避免了用户信息被第三方劫持;Cookie可以搭配时间戳,来保证它的有效期,当有效期失效后,会重新使用用户名和密码登录,获取新的Cookie,这也有效地避免了第三方劫持Cookie,持续攻击服务器;而且这样也有效地解决了Http无状态的特性
常见的场景:比如说我们玩一个APP,登录之后,不需要再重复登录,但是很长时间没玩,你再次打开这个APP的时候,它会提示你再次登录,就是因为Cookie已经失效了,你需要重新获取新的Cookie。
当用户登录时,服务器端返回的Cookie
所以,如果服务器想要客户端保存Cookie到本地,那么在响应头中,就添加了一个Set-Cookie字段,从上图中,能够看到这个信息。
那么如何获取这个Cookie字段,就是通过OkHttp拦截器完成,因为Retrofit的底层也是OkHttp。
(1)拦截Cookie
在用户登录时,需要将服务器返回的cookie信息保存到本地,所以需要通过OkHttp拦截器,将“Set-Cookie”的字段值保存在本地
/**
* 在登录时获取
*/
public class CookieIntercepter implements Interceptor {
public CookieIntercepter() {
super();
}
@Override
public Response intercept(Chain chain) throws IOException {
//执行请求获取服务器返回的响应
Response response = chain.proceed(chain.request());
if(!response.headers("Set-Cookie").isEmpty()){
//解析Cookie
for (String header : response.headers("Set-Cookie")) {
if(header.contains("JSESSIONID")){
String cookie = header.substring(header.indexOf("JSESSIONID"), header.indexOf(";"));
SPUtils.getInstance().saveInfo("cookie",cookie);
}
}
}
return response;
}
}
这样在本地就保存了服务器返回的cookie。
这里的JSESSIONID是对应服务器中的session的位置,所以在向服务器请求收藏时,要将这个cookie信息添加到请求头里,然后服务器接收到这个请求之后,会找到这个客户端对应的session,也就是说每个用户对应一个session,你在第一次登录的时候,服务器给你一个cookie,你保存在本地(客户端),对应的服务器也生成一个session保存客户端信息。
(2)添加头信息到请求
/**
* 将Cookie添加到请求的头部(在收藏时使用)
*/
public class AddCookieToHeader implements Interceptor {
public AddCookieToHeader() {
super();
}
@Override
public Response intercept(Chain chain) throws IOException {
Request.Builder request = chain.request().newBuilder();
String cookie = SPUtils.getInstance().getInfo("cookie", null);
if(cookie != null) {
request.addHeader("Cookie", cookie);
}
return chain.proceed(request.build());
}
}
然后可以设置OkHttp的拦截,设置到Retrofit的cilent中;
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new CookieIntercepter())
.build();
OkHttpClient cookieClient = new OkHttpClient.Builder()
.addInterceptor(new AddCookieToHeader())
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constant.BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
这个时候去服务端请求,就知道是哪个客户端来请求收藏信息,就不会再提示登录了。