Módulos comunes para solicitudes de red de Android
Las solicitudes Web HTTP comunes se dividen en solicitudes GET y POST. Python usa urllib y módulos de solicitudes, y Android usa okhttp y módulos de actualización . La relación entre okhttp y actualización es la misma que entre urllib y solicitudes. Ambos están reencapsulados sobre la base del primero para que sea más cómodo de usar.
El paquete de datos de la solicitud Web HTTP se puede dividir en dos formularios, el formulario de formulario y la cadena json En Python, estos dos formularios se distinguen por los parámetros del método de solicitudes, pero en Android, okhttp también tendrá envíos correspondientes. método de forma.
Cuando se recibe un paquete web, si se recibe la cadena json recibida, los datos deben deserializarse. El módulo de solicitudes en python nos ayuda a completar este trabajo, pero en Android, el módulo Gson debe introducirse para lograr el cambio de deserialización.
En las aplicaciones web del navegador, los archivos de cookies se usan para guardar información del usuario y los archivos xml se usan para lograr funciones similares en Android, por lo que también es necesario aprender a operar archivos xml en Android.
OKHTTP
Antes de usar okhttp, realice la siguiente configuración:
Importar, en build.gradle
implementation “com.squareup.okhttp3:okhttp:4.9.1”
Configuración, en AndroidManifest.xml, la etiqueta de la aplicación agregada por encima del mismo nivel
solo puede enviar solicitudes https.
Configuración, en AndroidManifest.xml, agregue android:networkSecurityConfig="@xml/network_security_config" dentro de la etiqueta de la aplicación
Cree una nueva carpeta xml en el directorio res, cree un nuevo archivo network_security_config.xml y escriba el siguiente contenido:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<!--禁用掉明文流量请求的检查-->
<base-config cleartextTrafficPermitted="true" />
</network-security-config>
Cree una solicitud GET ---> [crear hilo] --> de lo contrario informe de un error
String username = String.valueOf(txtUser.getText());
String password = String.valueOf(txtPwd.getText());
HashMap<String, String> dataMap = new HashMap<String, String>();
dataMap.put("username", username);
dataMap.put("password", password);
// 1. 将用户名和密码 发送到后台 (第三方 OKHttp)
// 1.1 引入依赖 bulid.gradle 文件中 引入 implementation "com.squareup.okhttp3:okhttp:4.9.1"
// 1.2 在Android中,默认不允许发送网络请求; 在AndroidManifest.xml 中 配置 <uses-permission android:name="android.permission.INTERNET"/>
// 1.3 调用 OKHttp包去发送请求。
// 1.3.1 创建 GET 请求 ---> [创建线程]--> 否则报错
// 创建线程并执行 run 方法
new Thread(){
@Override
public void run(){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url("https://api.luffycity.com/api/v1/course/actual/?category_id=1").build();
Call call = client.newCall(request);
try {
Response response = call.execute(); // 发送请求
ResponseBody body = response.body();
String resString = body.string();
Log.i("登录界面--->", resString);
// 获取数据并处理
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
Crear solicitud POST ---> [crear hilo]
formularioFormato de formulario
Los paquetes se envían en un formato de formulario como:
username=xxxx&password=123
new Thread(){
@Override
public void run(){
OkHttpClient client = new OkHttpClient();
// 构建请求体
FormBody form = new FormBody.Builder().add("username", "xxxx").add("password", "123").build();
// form ---> post 请求体
Request request = new Request.Builder().url("https://api.luffycity.com/api/v1/auth/password/login/?loginWay=password").post(form).build();
Call call = client.newCall(request);
try {
Response response = call.execute(); // 发送请求
ResponseBody body = response.body();
String resString = body.string();
Log.i("登录界面--->", resString);
// 获取数据并处理
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
formato json
El paquete de datos se envía en formato json, por ejemplo:
{
username:"xxxx",
password:123,
}
new Thread() {
@Override
public void run() {
OkHttpClient client = new OkHttpClient();
// 构建请求体
// FormBody form = new FormBody.Builder().add("username", "xxxx").add("password", "123").build();
//JSONObject json = new JSONObject();
//json.put("username", "dk");
//json.put("password", "123");
JSONObject json = new JSONObject(dataMap);
String jsonString = json.toString();
RequestBody form = RequestBody.create(MediaType.parse("application/json;charset=utf-8"), toString());
// form ---> post 请求体
Request request = new Request.Builder().url("https://api.luffycity.com/api/v1/auth/password/login/?loginWay=password").post(form).build();
Call call = client.newCall(request);
try {
Response response = call.execute(); // 发送请求
ResponseBody body = response.body();
String resString = body.string();
// Json反序列化,字符串转换成对象.
// json.load(json字符串) --> python
// Android 需要 GSON --> 引入 (implementation "com.google.code.gson:gson:2.8.6")
//
String responseString = "{\"token\": \"dsajkdhjksald\", \"url\": \"https://www.httpbin.org/post/\",\"dataList\":[{\"id\": 1, \"name\": \"dk\"},{\"id\": 2, \"name\": \"dkk\"}]}";
HttpResponse res = new Gson().fromJson(responseString, HttpResponse.class);
Log.e("登录界面--->", res.toString()); //HttpResponse{url='https://www.httpbin.org/post/', origin='101.248.149.62', dataList=[Item{id=1, name='dk'}, Item{id=2, name='dkk'}]}
// 保存起来:cookies, localstorage
// andorid -> xml 文件 -> data/data/com.example.myapplication/shared_prefs
SharedPreferences sharedPreferences = getSharedPreferences("sp_MyApplication", MODE_PRIVATE);
SharedPreferences.Editor editor= sharedPreferences.edit();
editor.putString("token", res.token);
editor.commit();
// 跳转首页
Intent in = new Intent(mcontext, IndexActivity.class);
startActivity(in);
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
La diferencia entre los dos es:
El formato del formulario usa FormBody para construir el cuerpo de la solicitud.
El formato de cadena json usa tanto JSONObject como RequestBody para construir el cuerpo de la solicitud.
interceptor de solicitudes
Parte de la información del encabezado de la solicitud es transportada por cada solicitud HTTP. Esta información común del encabezado de la solicitud es implementada por el middleware en el marco del rastreador scrapy de python y por los interceptores de solicitudes en okhttp de la aplicación Android. El siguiente es el código de prueba simple de Interceptor.
// 4. 发送请求拦截器
Interceptor interceptor = new Interceptor() {
@NonNull
@Override
public Response intercept(@NonNull Chain chain) throws IOException {
String sign = "sfsadsadsa";
// 请求还未发送,在请求体中增加了一个请求头
Request request = chain.request().newBuilder().addHeader("x-gorgon", sign).build();
Response response = chain.proceed(request);
return response;
}
};
new Thread() {
@Override
public void run() {
// 加入拦截器
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
// 构建请求体
// FormBody form = new FormBody.Builder().add("username", "xxxx").add("password", "123").build();
//JSONObject json = new JSONObject();
//json.put("username", "dk");
//json.put("password", "123");
JSONObject json = new JSONObject(dataMap);
String jsonString = json.toString();
RequestBody form = RequestBody.create(MediaType.parse("application/json;charset=utf-8"), toString());
// form ---> post 请求体
Request request = new Request.Builder().url("https://api.luffycity.com/api/v1/auth/password/login/?loginWay=password").post(form).build();
Call call = client.newCall(request);
try {
Response response = call.execute(); // 发送请求
ResponseBody body = response.body();
String resString = body.string();
// Json反序列化,字符串转换成对象.
// json.load(json字符串) --> python
// Android 需要 GSON --> 引入 (implementation "com.google.code.gson:gson:2.8.6")
//
String responseString = "{\"token\": \"dsajkdhjksald\", \"url\": \"https://www.httpbin.org/post/\",\"dataList\":[{\"id\": 1, \"name\": \"dk\"},{\"id\": 2, \"name\": \"dkk\"}]}";
HttpResponse res = new Gson().fromJson(responseString, HttpResponse.class);
Log.e("登录界面--->", res.toString()); //HttpResponse{url='https://www.httpbin.org/post/', origin='101.248.149.62', dataList=[Item{id=1, name='dk'}, Item{id=2, name='dkk'}]}
// 保存起来:cookies, localstorage
// andorid -> xml 文件 -> data/data/com.example.myapplication/shared_prefs
SharedPreferences sharedPreferences = getSharedPreferences("sp_MyApplication", MODE_PRIVATE);
SharedPreferences.Editor editor= sharedPreferences.edit();
editor.putString("token", res.token);
editor.commit();
// 跳转首页
Intent in = new Intent(mcontext, IndexActivity.class);
startActivity(in);
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
La diferencia con el interceptor anterior :
Creó un interceptor antes de crear okhttp
Al crear okhttp, agregue un interceptor
NO_PROXY
Para evitar la captura de paquetes, algunas aplicaciones usarán el parámetro NO_PROXY de okhttp para prohibir que el teléfono Android configure un proxy del sistema. En este caso, puede usar la aplicación Drony para capturar paquetes sin un proxy, o puede usar aplicaciones como como Little Yellow Bird para capturar paquetes con una VPN local.
Para obtener información sobre la captura de paquetes sin agente, consulte: Análisis del rastreador de Python de la captura de paquetes en el modo sin agente de la aplicación y esquema de optimización antirrastreo para esto - Eeyhan - Blog Garden (cnblogs.com)
reacondicionar
Antes de usar la actualización, realice la siguiente configuración:
Introducción, implementación "com.squareup.retrofit2:retrofit:2.9.0" en build.gradle
El método de uso específico es el siguiente:
Escribir interfaz, declarar solicitud de red
package com.example.liyang;
package com.example.liyang;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.POST;
import retrofit2.http.GET;
import retrofit2.http.Query;
public interface HttpReq {
// 向/api/v1/post 发送POST请求,表单格式 name=xx&pwd=xxx
@POST("/api/v1/post")
@FormUrlEncoded
Call<ResponseBody> postLogin(@Field("name") String userName, @Field("pwd") String password);
// 向/api/v2/xxx 发送GET请求,表单格式 ?age=xxx
@GET("/api/v2/xxx")
Call<ResponseBody> getInfo(@Query("age") String age);
// 向/post/users 发送POST请求 json字符串格式 {name:xxxx,age:123}
@POST("/post/users")
Call<ResponseBody> postLoginJson(@Body RequestBody body);
}
Llame a la interfaz, pase parámetros a la interfaz y envíe una solicitud
new Thread() {
@Override
public void run() {
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://192.168.31.201:9999/").build();
HttpReq httpRequest = retrofit.create(HttpReq.class);
// http://192.168.31.201:9999/api/v1/post
// name=xx&pwd=xxx
Call<ResponseBody> call = httpRequest.postLogin("wupeiqi", "666");
try {
ResponseBody responseBody = call.execute().body();
String responseString = responseBody.string();
Log.i("登录", responseString);
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
new Thread() {
@Override
public void run() {
// http://192.168.31.201:9999/api/v2/xxx?age=123
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://192.168.31.201:9999/").build();
HttpReq req = retrofit.create(HttpReq.class);
Call<ResponseBody> call = req.getInfo("123");
try {
ResponseBody responseBody = call.execute().body();
String responseString = responseBody.string();
Log.e("Retrofit返回的结果", responseString);
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
new Thread() {
@Override
public void run() {
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://192.168.31.201:9999/").build();
HttpReq httpRequest = retrofit.create(HttpReq.class);
JSONObject json = new JSONObject(dataMap);
String jsonString = json.toString();
RequestBody form = RequestBody.create(MediaType.parse("application/json;charset=utf-8"),jsonString);
// http://192.168.31.201:9999/post/users
// {username:"root",password:"123456","sign":"xxxxdfsdfsdfsdfdfd"}
Call<ResponseBody> call = httpRequest.postLoginJson(form);
try {
ResponseBody responseBody = call.execute().body();
String responseString = responseBody.string();
Log.i("登录", responseString);
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
Precauciones:
Retrofit es una encapsulación adicional en okhttp. Se caracteriza por dividir la url solicitada en varios segmentos y especificarlos en diferentes lugares. La url se puede configurar de manera más flexible.
Al encontrar una interfaz escrita en retrofit, ya no se trata de encontrar la clase que la implementa, sino de encontrar la clase que la llama, empalmando la URL solicitada y encontrando los parámetros pasados.
El código es relativamente extenso y se centra en la forma de definir la interfaz, lo que determina el estilo de la solicitud, el método para llamar a la interfaz y los parámetros que se pasan. Las dos partes juntas determinan la URL de la solicitud.
GSON
Similar al módulo json en python, se usa para serializar objetos y deserializar cadenas json. Debe introducirse antes de usar Gson
implementation ‘com.google.code.gson:gson:2.8.6’
Serialización, objeto -> tipo de cadena
class HttpContext{
public int code;
public String message;
public HttpContext(int code,String msg){
this.code = code;
this.message = msg;
}
}
HttpContext obj = new HttpContext(1000,"成功");
String dataString = new Gson().toJson(obj); // '{"code":1000,"Message":"成功"}'
Deserialización, cadena -> objeto
// JSON格式
String dataString = "{\"status\": true, \"token\": \"fffk91234ksd\", \"name\": \"武沛齐\"}";
class HttpResponse{
public boolean status;
public String token;
public String name;
}
HttpResponse obj = new Gson().fromJson(dataString,HttpResponse.class);
// obj.status obj.name obj.token
Si hay anidamiento de diccionarios al deserializar
String responseString = "{\"origin\": \"110.248.149.62\",\"url\": \"https://www.httpbin.org/post\",\"dataList\":[{\"id\":1,\"name\":\"一个小黑\"},{\"id\":2,\"name\":\"eric\"}]}";
class Item {
public int id;
public String name;
}
public class HttpResponse {
public String url;
public String origin;
public ArrayList<Item> dataList;
}
HttpResponse obj = new Gson().fromJson(dataString, HttpResponse.class);
// obj.url obj.origin
Item objItem = obj.dataList.get(1);
// objItem.name
Guardar en archivo XML
Guardar en ubicación en el teléfono:
/data/data/com.example.liyang/shared_prefs/sp_city.xml
guardar token
SharedPreferences sp = getSharedPreferences("sp_city", MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putString("token","111111");
editor.commit();
eliminar token
SharedPreferences sp = getSharedPreferences("sp_city", MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.remove("token");
editor.commit();
ficha de lectura
SharedPreferences sp = getSharedPreferences("sp_city", MODE_PRIVATE);
String token = sp.getString("token","");
Recuerde que el objeto SharedPreferences se usa para leer y escribir el archivo XML local de la aplicación móvil
Los archivos XML son muy similares a las cookies, ya sea generados por un algoritmo local o devueltos por un servidor de solicitudes HTTP.
Resumir
jadx, jeb para descompilar el código de Android:
búsqueda por palabra clave
Consultar paso a paso según el proceso solicitado
llamada java
Nota: La pequeña aplicación puede revertirlo por completo al comprender el contenido anterior.