这是我参与2022首次更文挑战的第10天,活动详情查看:2022首次更文挑战
概念
【HTTP的状态管理】 由于 HTTP 协议是一款基于短连接的协议,所以HTTP协议是无状态的协议,我们在必要时需要实现 HTTP 协议的状态管理
无状态的意思是:服务端不保存客户端状态
【Cookie机制】 把数据保存在客户端 1、客户端发送 HTTP 协议的请求,在服务端接受并处理请求,返回响应数据包,并且在响应数据包中携带 Cookie 信息:(以消息头的形式) Set-Cookie:cishu=10 2、客户端接受响应数据,并且解析数据包获取 cookie 信息,保存到客户端中 3、当客户端发送后续请求时,需要在请求数据包中携带 cookie 信息:(以消息头的形式) Cookie:cishu=10 4、服务端接受请求,并且解析请求,获取 cookie 信息,执行业务,完成 HTTP 状态管理
【Cookie的限制】 1、不能存中文 2、不能存大量数据 3、安全性
【Session机制】 把数据保存在服务端 1、客户端发送 http 请求,服务端把数据存入服务端 session 对象中,并且分配一个 JSESSIONID,以 cookie 的方式返回给客户端。 Set-Cookie:JSESSIONID=ABCD 2、客户端接受响应,解析响应数据包,获取 JSESSIONID 保存到客户端。 3、当客户端发送后续请求时,需要在请求数据包中携带 JSESSIONID 一同发送该请求:(以 cookie 的方式) Cookie:JSESSIONID=ABCD 4、服务端接受请求数据包,获取 JSESSIONID,通过 JSESSIONID 找到上次请求保存到服务端的数据,处理业务,完成 HTTP 状态管理
【验证码业务】 验证码的租用:防止机器人恶意攻击服务器 1、获取验证码请求: 服务端生成验证码图片,把正确答案存入服务端。返回验证码图片的同时也返回 JSESSIONID 2、验证码验证 发送验证码请求,并且传递正确的验证码给服务端。于此同时,需要在请求数据包中携带 JSESSIONID。服务端才可以通过 JSESSIONID 获取正确的验证码并且进行比较。
我们上一节的登录并没有保存登录的状态,需要保存登录状态,需要给服务器传会JSESSIONID,用一个栗子做一下 我们需要一个这样的布局
activity_test
<?xml version="1.0" encoding="utf-8"?><?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="60dp"
android:layout_height="wrap_content"
android:text="用户名" />
<EditText
android:id="@+id/et_username"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="60dp"
android:layout_height="wrap_content"
android:text="密码" />
<EditText
android:id="@+id/et_password"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="60dp"
android:layout_height="wrap_content"
android:text="验证码" />
<EditText
android:id="@+id/et_captcha"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />
<ImageView
android:id="@+id/img_captcha"
android:layout_width="100dp"
android:layout_height="50dp" />
</LinearLayout>
<Button
android:id="@+id/btn_login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="确定" />
</LinearLayout>
TestActivity
public class TestActivity extends Activity implements View.OnClickListener {
private Button btn_login;
private EditText et_username;
private EditText et_password;
private EditText et_captcha;
private ImageView img_captcha;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case LOGIN_SUCCESS:
Toast.makeText(TestActivity.this, "登录成功", Toast.LENGTH_SHORT).show();
break;
case LOGIN_FAIL:
Toast.makeText(TestActivity.this, "登录失败:" + msg.obj, Toast.LENGTH_SHORT).show();
break;
case HANDLER_LOAD_IMAGE_SUCCESS:
if (bitmap != null) {
img_captcha.setImageBitmap(bitmap);
} else {
img_captcha.setImageResource(R.mipmap.ic_launcher);
}
break;
}
}
};
public static final int LOGIN_SUCCESS = 1;
public static final int LOGIN_FAIL = 2;
public static final int HANDLER_LOAD_IMAGE_SUCCESS = 3;
private Bitmap bitmap;
private String JSESSIONID;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
setViews();
//发送http请求,获取验证码图片
new Thread() {
@Override
public void run() {
try {
loadImage();
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
private void setViews() {
et_username = findViewById(R.id.et_username);
et_password = findViewById(R.id.et_password);
et_captcha = findViewById(R.id.et_captcha);
img_captcha = findViewById(R.id.img_captcha);
img_captcha.setOnClickListener(this);
btn_login = findViewById(R.id.btn_login);
btn_login.setOnClickListener(this);
}
private void loadImage() throws IOException {
URL url = new URL("http://域名/site/captcha.html?refresh=1&format=raw&user_agent=szyapp/android");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
InputStream is = conn.getInputStream();
//把输入流解析为Bitmap对象
bitmap = BitmapFactory.decodeStream(is);
//获取响应数据包中的Set-Cookie中的JSESSIONID
String val = conn.getHeaderField("Set-Cookie");
Log.i("JSESSIONID", val);
JSESSIONID = val.split(";")[0];
//把bitmap显示到Imageview,发消息给handler
handler.sendEmptyMessage(HANDLER_LOAD_IMAGE_SUCCESS);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_login:
new Thread() {
@Override
public void run() {
try {
login();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
}
}.start();
break;
case R.id.img_captcha:
new Thread() {
@Override
public void run() {
try {
loadImage();
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
break;
}
}
private void login() throws IOException, JSONException {
//1、URL
URL url = new URL("http://域名/site/login");
//2、HttpURLConnection
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//3、setRequestMethod setRequestProperty()
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("Cookie", JSESSIONID);
//4、doOutPut
conn.setDoInput(true);
OutputStream os = conn.getOutputStream();
//5、构建参数
String user_name = et_username.getText().toString();
String password = et_password.getText().toString();
String captcha = et_captcha.getText().toString();
String param = "user_agent=szyapp/android&user_name=" + user_name + "&password=" + password + "&verifyCode=" + captcha;
os.write(param.getBytes("utf-8"));
os.flush();
//6、inputStream
InputStream is = conn.getInputStream();
//7、is转换成String
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = "";
while ((line = reader.readLine()) != null) {
sb.append(line);
}
String json = sb.toString();
//7、解析json
JSONObject obj = new JSONObject(json);
String res = obj.getString("code");
//8、发消息给Handler
if (res.equals("0")) {
//成功
handler.sendEmptyMessage(LOGIN_SUCCESS);
} else {
//失败
Message msg = new Message();
msg.what = LOGIN_FAIL;
msg.obj = obj.getString("message");
handler.sendMessage(msg);
}
}
}
运行结果: