Para configure regras baseadas em cenário anti-crawler para o gerenciamento de bots no console, você deve integrar o SDK de App Protection do WAF. Este tópico explica como integrar o SDK a aplicativos Android.
Contexto
O SDK de App Protection assina as requisições dos clientes do aplicativo. O servidor do Web Application Firewall (WAF) verifica essas assinaturas de requisição para identificar riscos, bloquear requisições maliciosas e proteger o aplicativo.
Limitações
Para Android, o SDK oferece suporte às arquiteturas arm64-v8a e armeabi-v7a.
O nível da API do Android deve ser 16 ou superior.
O método init pode ser demorado. Para garantir a proteção total, aguarde pelo menos 2 segundos entre a chamada do método init e o método vmpSign. Esse atraso é recomendado para uma proteção ideal, mas não é obrigatório. Você pode ajustar esse atraso com base nas necessidades do seu negócio, mas um atraso menor pode impedir que os recursos de segurança funcionem plenamente.
-
Ao usar o ProGuard para obfuscação de código, utilize a opção -keep para preservar os métodos do SDK. Por exemplo:
-keep class com.aliyun.TigerTally.** {*;} -keep class com.aliyun.captcha.* {*;} -keepclassmembers,allowobfuscation class * { @com.alibaba.fastjson.annotation.JSONField <fields>; } -keep class com.alibaba.fastjson.** {*;}
Pré-requisitos
-
Obtenha o SDK para o seu aplicativo Android.
Para obter o SDK, envie um ticket para nossos especialistas técnicos do product.
NotaO SDK para Android inclui dois arquivos AAR: AliTigerTally_X.Y.Z.aar e AliCaptcha_X.Y.Z.aar, em que X.Y.Z é o número da versão.
-
Você obteve a chave de autenticação do SDK (também conhecida como appkey).
Após ative o Gerenciamento de Bots, você pode Faça login no console do Web Application Firewall 3.0. Na barra de menu superior, selecione o grupo de recursos e a região (Chinese Mainland ou Outside Chinese Mainland) da instância do WAF.. No painel de navegação à esquerda, escolha . acesse a aba App Protection e clique em Obtain and Copy AppKey no canto superior direito para recuperar a chave de autenticação do SDK. Essa chave é necessária para inicializar o SDK e deve ser incluída no seu código de integração.
NotaCada conta Alibaba Cloud possui uma appkey exclusiva para todos os nomes de domínio protegidos pelo WAF. Essa appkey é usada para a integração do SDK em aplicativos Android, iOS e HarmonyOS.
Exemplo de chave de autenticação:
****OpKLvM6zliu6KopyHIhmneb_****u4ekci2W8i6F9vrgpEezqAzEzj2ANrVUhvAXMwYzgY_****vc51aEQlRovkRoUhRlVsf4IzO9dZp6nN_****Wz8pk2TDLuMo4pVIQvGaxH3vrsnSQiK****.
Etapa 1: crie um projeto
No Android Studio, siga o assistente de configuração para criar um novo projeto Android. A estrutura de diretórios do projeto é a seguinte:
tigertally-demo-apk [TigerTallyDemo]
.gradle
.idea
app
build
libs
AliCaptcha_xxx.aar
AliTigerTally_xxx.aar
src
androidTest
main
test [unitTest]
.gitignore
build.gradle
proguard-rules.pro
gradle
wrapper
gradle-wrapper.jar
gradle-wrapper.properties
.gitignore
.java-version
build.gradle
gradle.properties
gradlew
gradlew.bat
local.properties
settings.gradle
tigertally.jks
External Libraries
Scratches and Consoles
Etapa 2: Integrar o AAR
Extraia o arquivo do SDK tigertally-X.Y.Z-xxxxxx-android.tgz e copie todos os arquivos AAR da pasta extraída para o diretório libs do seu módulo principal (o caminho exato depende da configure do seu projeto).
-
Abra o arquivo build.gradle do seu aplicativo e adicione dependências para AliTigerTally_X.Y.Z.aar e AliCaptcha_X.Y.Z.aar a partir do diretório
libs.ImportanteSubstitua X.Y.Z nos nomes dos arquivos AliTigerTally_X.Y.Z.aar e AliCaptcha_X.Y.Z.aar pelo número da versão dos seus arquivos AAR.
A configure é a seguinte:
dependencies { // ... implementation files('libs/AliTigerTally_X.Y.Z.aar') implementation files('libs/AliCaptcha_X.Y.Z.aar') // third-party library dependencies implementation 'com.alibaba:fastjson:1.2.83_noneautotype' implementation 'com.squareup.okhttp3:okhttp:3.11.0' implementation 'com.squareup.okio:okio:1.14.0' }
Etapa 3: Filtrar arquiteturas de CPU SO
Se o seu projeto ainda não utilizou arquivos SO, adicione a seguinte configuração ao seu arquivo build.gradle.
android {
defaultConfig {
ndk {
abiFilters 'arm64-v8a', 'armeabi-v7a'
}
}
}
Etapa 4: Solicitar permissões
-
Permissão obrigatória
<uses-permission android:name="android.permission.INTERNET"/> -
Permissões opcionais
<uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Para o Android 6.0 e versões posteriores, você deve solicitar dinamicamente android.permission.READ_EXTERNAL_STORAGE e android.permission.WRITE_EXTERNAL_STORAGE.
Etapa 5: Adicionar código de integração
1. Adicionar arquivos de cabeçalho
import com.alibaba.fastjson.*;
import com.aliyun.tigertally.*;
2. Configurar a assinatura de dados
-
defina um ID personalizado para cada usuário final. Isso permite configure as políticas de mitigação do WAF de forma mais flexível.
/** * Sets the user account. * * @param account The user account. * @return An error code. */ public static int setAccount(String account)-
Parâmetros:
account: String. Uma string que identifica um usuário. Recomendamos o uso de um formato com dados mascarados.
Valor de retorno: int. Retorna 0 em caso de sucesso ou -1 em caso de falha.
-
Código de exemplo:
// For a guest, you can skip setAccount and directly initialize the SDK. After the user logs in, call setAccount and reinitialize. String account = "user001"; TigerTallyAPI.setAccount(account);
-
-
Inicialize o SDK e execute uma coleta inicial de dados.
Uma coleta inicial de dados reúne as informações do dispositivo uma única vez. Chame a função
initnovamente para realizar uma nova coleta com base nos requisitos do seu negócio. Três modos de coleta estão disponíveis: coleta completa, coleta de privacidade personalizada e coleta sem privacidade. O modo sem privacidade não coleta dados de campos relacionados à privacidade do usuário final, incluindo: imei, imsi, simSerial, wifiMac, wifiList, bluetoothMac e androidId.NotaSelecione um modo de coleta que esteja alinhado com seus requisitos de conformidade e garanta a integridade dos dados. Dados completos melhoram a identificação de riscos.
// Initialization callback public interface TTInitListener { // The code parameter indicates the status code of the interface call. void onInitFinish(int code); } /** * Initializes the SDK with a callback. * * @param context The application context. * @param appkey The SDK appkey. * @param collectType The data collection mode. * @param otherOptions Optional parameters. * @param listener The initialization callback. * @return An error code. */ public static int init(Context context, String appkey, int collectType, Map<String, String> otherOptions, TTInitListener listener);-
Parâmetros:
context: Context. O contexto do seu aplicativo.
appkey: String. A appkey do seu SDK.
-
collectType: int. O modo de coleta. Valores válidos:
Parâmetro
Descrição
Exemplo
TT_DEFAULT
Coleta todos os dados.
TigerTallyAPI.TT_DEFAULT
TT_NO_BASIC_DATA
Não coleta dados básicos do dispositivo.
Inclui: nome do dispositivo (Build.DEVICE), versão do Android (Build.VERSION#RELEASE) e resolução da tela.
TigerTallyAPI.X | TigerTallyAPI.Y
(Indica que nem X nem Y são coletados. X e Y representam os nomes dos campos de itens específicos.)
TT_NO_IDENTIFY_DATA
Não coleta dados de identificação do dispositivo.
Inclui: IMEI, IMSI, SimSerial, BuildSerial (SN) e endereço MAC.
TT_NO_UNIQUE_DATA
Não coleta dados de identificadores exclusivos.
Inclui: OAID, Google Advertising ID e Android ID.
TT_NO_EXTRA_DATA
Não coleta dados estendidos do dispositivo.
Inclui: lista de aplicativos maliciosos/área cinzenta, IP de LAN, IP de DNS, informações de Wi-Fi conectado (SSID, BSSID), lista de Wi-Fi próximo, informações de localização e informações de sensor.
TT_NOT_GRANTED
Não coleta nenhum dos dados de privacidade anteriores.
TigerTallyAPI.TT_NOT_GRANTED
-
otherOptions: Map<String, String>. Parâmetros opcionais de coleta de dados. Pode ser nulo. Parâmetros disponíveis:
Parâmetro
Descrição
Exemplo
IPv6
Especifique se deve usar um nome de domínio IPv6 para relatar informações do dispositivo.
0 (padrão): Usa um nome de domínio IPv4.
1: Usa um nome de domínio IPv6.
1
Intl
Especifique se deve relatar informações do dispositivo para uma região fora da China continental.
0 (padrão): Relata para a China continental.
1: Relata para uma região fora da China continental.
1
CustomUrl
O nome de domínio do servidor de relatório de dados.
https://cloudauth-device.us-west-1.aliyuncs.com
CustomHost
O host do servidor de relatório de dados.
cloudauth-device.us-west-1.aliyuncs.com
NotaPara a maioria dos sites internacionais, defina apenas o parâmetro Intl. Para relatar dados para um site específico, defina os parâmetros CustomUrl e CustomHost. Os sites disponíveis incluem:
Se
Intlestiver definido como0, os dados são relatados para o site padrão em China (Shanghai): https://cloudauth-device.cn-shanghai.aliyuncs.com-
Se
Intlestiver definido como1:O site padrão é Singapore: https://cloudauth-device.ap-southeast-1.aliyuncs.com
Indonesia (Jakarta): https://cloudauth-device.ap-southeast-5.aliyuncs.com
US (Silicon Valley): https://cloudauth-device.us-west-1.aliyuncs.com
Germany (Frankfurt): https://cloudauth-device.eu-central-1.aliyuncs.com
China (Hong Kong): https://cloudauth-device.cn-hongkong.aliyuncs.com
-
listener: TTInitListener. O callback de inicialização do SDK. Use o callback para verificar o status de inicialização. Pode ser nulo.
TTCode
Código
Descrição
TT_SUCCESS
0
SDK inicializado com sucesso.
TT_NOT_INIT
-1
SDK não inicializado.
TT_NOT_PERMISSION
-2
O SDK não recebeu as permissões necessárias do Android.
TT_UNKNOWN_ERROR
-3
Erro desconhecido do sistema.
TT_NETWORK_ERROR
-4
Erro de rede.
TT_NETWORK_ERROR_EMPTY
-5
Erro de rede: resposta vazia.
TT_NETWORK_ERROR_INVALID
-6
Formato de resposta de rede inválido.
TT_PARSE_SRV_CFG_ERROR
-7
Falha ao analisar a configuração do servidor.
TT_NETWORK_RET_CODE_ERROR
-8
O gateway retornou uma resposta de falha.
TT_APPKEY_EMPTY
-9
Appkey vazia.
TT_PARAMS_ERROR
-10
Parâmetro inválido.
TT_FGKEY_ERROR
-11
Erro de cálculo da chave.
TT_APPKEY_ERROR
-12
Incompatibilidade entre a versão do SDK e a appkey.
Valor de retorno: int. Retorna 0 em caso de sucesso ou -1 em caso de falha.
-
Código de exemplo:
// The appkey is the authentication key assigned on the Alibaba Cloud platform. final String appkey="******"; // Optional parameters to configure IPv6 and international reporting. Map<String, String> options = new HashMap<>(); options.put("IPv6", "0"); // Use IPv4. options.put("Intl", "0"); // Report to the Chinese mainland. //options.put("Intl", "1"); // Report to a region outside the Chinese mainland. // Report to US (Silicon Valley). //options.put("CustomUrl", "https://cloudauth-device.us-west-1.aliyuncs.com"); //options.put("CustomHost", "cloudauth-device.us-west-1.aliyuncs.com"); // An initial data collection gathers device information one time. You can call the init function again to perform a new collection based on your business requirements. // Full collection. int ret = TigerTallyAPI.init(this.getApplicationContext(), appkey, TigerTallyAPI.TT_DEFAULT, options, null); // Specify privacy data to collect. You can combine different flags by using the "|" operator. int privacyFlag = TigerTallyAPI.TT_NO_BASIC_DATA | TigerTallyAPI.TT_NO_UNIQUE_DATA; int ret = TigerTallyAPI.init(this.getApplicationContext(), appkey, privacyFlag, options, null); // Do not collect privacy fields. int ret = TigerTallyAPI.init(this.getApplicationContext(), appkey, TigerTallyAPI.TT_NOT_GRANTED, options, null); Log.d("AliSDK", "ret:" + ret);
-
-
Calcule o hash dos dados.
Este método de assinatura personalizada calcula um hash dos dados de entrada e retorna a string
whashgerada como os dados de assinatura personalizada. Para requisições POST, PUT e PATCH, passe o corpo da requisição. Para requisições GET e exclua, passe a URL completa. A stringwhashdeve ser adicionada ao campo ali_sign_whash no cabeçalho da requisição HTTP.// Request type: public enum RequestType { GET, POST, PUT, PATCH, DELETE } /** * Hashes data for a custom signature. * * @param type The request type. * @param input The data to hash. * @return The whash string. */ public static String vmpHash(RequestType type, byte[] input);Parâmetros:
-
type: RequestType. O tipo de requisição. Valores válidos:
GET: Uma requisição GET.
POST: Uma requisição POST.
PUT: Uma requisição PUT.
PATCH: Uma requisição PATCH.
exclua: Uma requisição exclua.
input: byte[]. Os dados para calcular o hash.
Valor de retorno: String. Retorna a string
whash.-
Código de exemplo:
// GET request String url = "https://tigertally.aliyun.com/apptest"; String whash = TigerTallyAPI.vmpHash(TigerTallyAPI.RequestType.GET, url.getBytes()); Log.d("AliSDK", "whash:" + whash); // POST request String body = "hello world"; String whash = TigerTallyAPI.vmpHash(TigerTallyAPI.RequestType.POST, body.getBytes()); Log.d("AliSDK", "whash:" + whash);NotaEste método não é necessário para a assinatura padrão. Para assinatura personalizada, chame este método para calcular o hash dos dados antes de assiná-los.
-
Assine os dados.
Este método usa a tecnologia VMP para assinar os dados de entrada e retorna uma string
wtokenpara autenticação da requisição./** * Signs the data. * * @param type The signature type. * @param input The data to sign. * @return The wtoken string. */ public static String vmpSign(int type, byte[] input);-
Parâmetros:
type: int. O tipo de assinatura de dados. O valor deve ser 1.
input: byte[]. Os dados a serem assinados. Geralmente, é todo o corpo da requisição ou a string whash da assinatura personalizada.
Valor de retorno: String. Retorna a string
wtoken.-
Código de exemplo:
// Use this code if default signing is configured in the console (custom signing is not selected). String body = "i am the request body, encrypted or not!"; String wtoken = TigerTallyAPI.vmpSign(1, body.getBytes("UTF-8")); Log.d("AliSDK", "wToken:" + wtoken); // Use this code if custom signing is configured in the console. // GET request String url = "https://tigertally.aliyun.com/apptest"; String whash = TigerTallyAPI.vmpHash(TigerTallyAPI.RequestType.GET, url.getBytes()); String wtoken = TigerTallyAPI.vmpSign(1, whash.getBytes()); Log.d("AliSDK", "whash:" + whash + ", wtoken:" + wtoken); // POST request String body = "hello world"; String whash = TigerTallyAPI.vmpHash(TigerTallyAPI.RequestType.POST, body.getBytes()); String wtoken = TigerTallyAPI.vmpSign(1, whash.getBytes()); Log.d("AliSDK", "whash:" + whash + ", wtoken:" + wtoken);NotaAo chamar vmpHash para assinatura personalizada, o parâmetro input do método vmpSign é a string
whashgerada. Ao configure as políticas anti-bot do aplicativo, o valor do Custom Signature Field deve ser definido comoali_sign_whash.Ao chamar vmpHash para gerar uma string
whashpara uma requisição GET, certifique-se de que a URL de entrada seja idêntica à URL final usada na requisição de rede. Preste atenção especial à codificação da URL, pois alguns frameworks codificam automaticamente caracteres chineses ou parâmetros.O parâmetro input do método vmpHash não aceita um array de bytes vazio ou uma string vazia. Se a entrada for uma URL, ela deve conter um caminho ou parâmetros.
Ao chamar vmpSign, se o corpo da requisição estiver vazio (por exemplo, em uma requisição GET ou uma requisição POST com corpo vazio), passe um objeto null ou o valor em bytes de uma string vazia, como "".getBytes("UTF-8").
-
Se o valor de
whashouwtokenfor uma das seguintes strings, o SDK retornou um erro:you must call init first: O SDK não está inicializado. Chame
init()primeiro.you must input correct data: Dados de entrada inválidos.
you must input correct type: Tipo de entrada inválido.
-
3. Realizar a verificação secundária
-
Avalie o resultado.
Verifique os campos cookie e body na response para determinar se a verificação secundária é necessária. Antes de chamar este método, mescle várias entradas Set-Cookie em uma única string de cookie.
/** * Determines whether to perform secondary verification. * * @param cookie The cookie string. * @param body The body string. * @return 0 for pass, or 1 for secondary verification required. */ public static int cptCheck(String cookie, String body)-
Parâmetros:
cookie: String. Todos os cookies da response HTTP.
body: String. O body completo da response HTTP.
Valor de retorno: int. Retorna 0 se a requisição for aprovada ou 1 se a verificação secundária for necessária.
-
Código de exemplo:
String cookie = "key1=value1;kye2=value2;"; String body = "...."; int recheck = TigerTallyAPI.cptCheck(cookie, body); Log.d("AliSDK", "recheck:" + recheck);
-
-
crie um slider.
Se cptCheck retornar 1, crie um objeto slider. O objeto TTCaptcha fornece os métodos
show()edismiss()para exibir e ocultar a janela do slider, respectivamente. TTOption encapsula os parâmetros configure do slider, e TTListener fornece callbacks para os estados de sucesso e falha. Para usar uma janela de slider personalizada, passe a URL da página personalizada. Há suporte tanto para arquivos HTML locais quanto para páginas remotas./** * Creates a slider object. * * @param activity The activity where the slider is displayed. * @param option The slider parameters. * @param listener The callback for the slider. * @return The slider verification object. */ public static TTCaptcha cptCreate(Activity activity, TTOption option, TTListener listener); /** * The slider object. */ public class TTCaptcha { /** * Displays the slider. */ public void show(); /** * Hides the slider. */ public void dismiss(); /** * Gets the slider traceId for data statistics. */ public String getTraceId(); } /** * The slider parameters. */ public static class TTOption { // Specifies whether the slider can be dismissed by clicking a blank area. public boolean cancelable; // The custom page. Local HTML files and remote URLs are supported. public String customUri; // The language. public String language; } /** * The callback for slider events. */ public interface TTListener { /** * Called on successful verification. * * @param captcha The slider object. * @param data The token. Defaults to certifyId. */ void success(TTCaptcha captcha, String data); /** * Called on verification failure. * * @param captcha The slider object. * @param code The error code. */ void failed(TTCaptcha captcha, String code); }-
Parâmetros:
activity: Activity. A activity da página atual.
option: TTOption. Os parâmetros de configure do slider.
listener: TTListener. O callback de status do slider.
Valor de retorno: TTCaptcha. O objeto slider.
Código de exemplo:
TTCaptcha.TTOption option = new TTCaptcha.TTOption(); // option.customUri = "file:///android_asset/ali-tt-captcha-demo.html"; option.language = "cn"; option.cancelable = false; TTCaptcha captcha = TigerTallyAPI.cptCreate(this, option, new TTCaptcha.TTListener() { @Override public void success(TTCaptcha captcha, String data) { Log.d(TAG, "captcha check success:" + data); } @Override public void failed(TTCaptcha captcha, String code) { Log.d(TAG, "captcha check failed:" + code); } }); captcha.show();NotaUma falha na verificação indica que uma exceção foi detectada após o usuário concluir o desafio do slider.
A lista a seguir descreve os códigos de erro:
1001: Falha na verificação.
1002: Exceção do sistema.
1003: Parâmetro inválido.
1005: Verificação cancelada.
8001: Falha ao exibir o slider.
8002: Dados de verificação do slider anormais.
8003: Exceção interna na verificação do slider.
8004: Erro de rede.
-
Exemplo de melhor prática
package com.aliyun.tigertally.apk;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import com.aliyun.TigerTally.TigerTallyAPI;
import com.aliyun.TigerTally.captcha.api.TTCaptcha;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class DemoActivity extends AppCompatActivity {
private final static String TAG = "TigerTally-Demo";
private final static String APP_HOST = "******";
private final static String APP_URL = "******";
private final static String APP_KEY = "******";
private final static OkHttpClient okHttpClient = new OkHttpClient();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo);
doTest();
}
private void doTest() {
Log.d(TAG, "captcha flow");
new Thread(() -> {
// Initialize the SDK.
Map<String, String> options = new HashMap<>();
//options.put("Intl", "1"); // To enable international reporting.
// Use full data collection mode.
int ret = TigerTallyAPI.init(this, APP_KEY, TigerTallyAPI.TT_DEFAULT, options, null);
// Alternatively, do not collect privacy fields.
// int ret = TigerTallyAPI.init(this, APP_KEY, TigerTallyAPI.TT_NOT_GRANTED, null, null);
Log.d(TAG, "tiger tally init: " + ret);
// Wait for initialization to complete.
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Sign the data.
String data = "hello world";
String whash = null, wtoken = null;
// Use custom signing.
whash = TigerTallyAPI.vmpHash(TigerTallyAPI.RequestType.POST, data.getBytes());
wtoken = TigerTallyAPI.vmpSign(1, whash.getBytes());
Log.d(TAG, "tiger tally vmp: " + whash + ", " + wtoken);
// Use standard signing.
// wtoken = TigerTallyAPI.vmpSign(1, data.getBytes());
// Log.d(TAG, "tiger tally vmp: " + wtoken);
// Send the request.
doPost(APP_URL, APP_HOST, whash, wtoken, data, (code, cookie, body) -> {
// Check if the slider is required.
int recheck = TigerTallyAPI.cptCheck(cookie, body);
Log.d(TAG, "captcha check result: " + recheck);
if (recheck == 0) return;
this.runOnUiThread(this::doShow);
});
}).start();
}
// Display the slider.
public void doShow() {
Log.d(TAG, "captcha show");
TTCaptcha.TTOption option = new TTCaptcha.TTOption();
// option.customUri = "file:///android_asset/ali-tt-captcha-demo.html";
option.language = "cn";
option.cancelable = false;
TTCaptcha captcha = TigerTallyAPI.cptCreate(this, option, new TTCaptcha.TTListener() {
@Override
public void success(TTCaptcha captcha, String data) {
Log.d(TAG, "captcha check success:" + data);
}
@Override
public void failed(TTCaptcha captcha, String code) {
Log.d(TAG, "captcha check failed:" + code);
}
});
captcha.show();
}
// Send the request.
public static void doPost(String url, String host, String whash, String wtoken, String body, Callback callback) {
Log.d(TAG, "start request post");
int responseCode = 0;
String responseBody = "";
StringBuilder responseCookie = new StringBuilder();
try {
Request.Builder builder = new Request.Builder()
.url(url)
.addHeader("wToken", wtoken)
.addHeader("Host", host)
.post(RequestBody.create(MediaType.parse("text/x-markdown"), body.getBytes()));
if (whash != null) {
builder.addHeader("ali_sign_whash", whash);
}
Response response = okHttpClient.newCall(builder.build()).execute();
responseCode = response.code();
responseBody = response.body() == null ? "" : response.body().string();
for (String item : response.headers("Set-Cookie")) {
responseCookie.append(item).append(";");
}
Log.d(TAG, "response code:" + responseCode);
Log.d(TAG, "response cookie:" + responseCookie);
Log.d(TAG, "response body:" + (responseBody.length() > 100 ? responseBody.substring(0, 100) : ""));
if (response.isSuccessful()) {
Log.d(TAG, "success: " + response.code() + ", " + response.message());
} else {
Log.e(TAG, "failed: " + response.code() + ", " + response.message());
}
response.close();
} catch (Exception e) {
e.printStackTrace();
responseCode = -1;
responseBody = e.toString();
} finally {
if (callback != null) {
callback.onResponse(responseCode, responseCookie.toString(), responseBody);
}
}
}
public interface Callback {
void onResponse(int code, String cookie, String body);
}
}