EasyClick 入门指南:HTTP 网络请求与 API 对接实战

EasyClick 入门指南:HTTP 网络请求与 API 对接实战

本文是 EasyClick 入门系列第十六篇

HTTP 网络请求与 API 对接实战

目录

  1. 前言
  2. [HTTP 基础概念](#HTTP 基础概念)
  3. [GET 请求详解](#GET 请求详解)
  4. [POST 请求详解](#POST 请求详解)
  5. 文件上传与下载
  6. [JSON 数据处理](#JSON 数据处理)
  7. [WebSocket 实时通信](#WebSocket 实时通信)
  8. 实战案例
  9. 常见问题

一、前言

为什么需要 HTTP 请求?

在自动化脚本中,HTTP 网络请求是实现以下功能的关键:

  • 云端数据交互:从服务器获取配置、提交执行结果
  • 第三方 API 对接:调用短信接口、打码平台、AI 识别等
  • 文件传输:上传截图、下载更新包
  • 实时通信:WebSocket 实现长连接数据推送

EasyClick HTTP 模块特点

  • 支持 GET/POST/PUT 等多种请求方式
  • 支持文件上传下载(含断点续传)
  • 支持 WebSocket 实时通信
  • 支持自定义请求头、Cookie、代理
  • 所有运行模式通用(无障碍/代理/Root/HID)

二、HTTP 基础概念

2.1 HTTP 请求流程

复制代码
脚本 -> 构建请求参数 -> 发送请求 -> 服务器处理 -> 返回响应 -> 解析数据

2.2 常用请求方法

方法 用途 示例场景
GET 获取数据 查询服务器配置、获取任务列表
POST 提交数据 提交执行结果、用户登录
PUT 更新数据 更新配置信息

2.3 HTTP 响应状态码

状态码 含义 处理方式
200 请求成功 正常处理响应数据
404 资源不存在 检查 URL 是否正确
500 服务器错误 稍后重试或联系服务端
403 权限不足 检查 Token 或权限配置

三、GET 请求详解

3.1 简单 GET 请求

javascript 复制代码
/**
 * 发送简单的 GET 请求
 * @param url 请求地址
 * @param timeout 超时时间(毫秒)
 * @param headers 请求头
 * @return string 响应内容
 */
function simpleGetRequest() {
    var url = "https://api.example.com/config";
    var timeout = 10000; // 10秒超时
    var headers = {
        "User-Agent": "EasyClick/1.0"
    };
    
    // 发送 GET 请求
    var response = http.httpGetDefault(url, timeout, headers);
    
    if (response) {
        logd("GET 请求成功,响应内容: " + response);
        return response;
    } else {
        loge("GET 请求失败");
        return null;
    }
}

// 使用示例
simpleGetRequest();

3.2 带参数的 GET 请求

javascript 复制代码
/**
 * 发送带参数的 GET 请求
 * @param url 请求地址
 * @param params 参数对象
 * @param timeout 超时时间
 * @param headers 请求头
 * @return string 响应内容
 */
function getRequestWithParams() {
    var url = "https://api.example.com/search";
    
    // 请求参数
    var params = {
        "keyword": "自动化测试",
        "page": "1",
        "pageSize": "20"
    };
    
    var timeout = 10000;
    var headers = {
        "User-Agent": "EasyClick/1.0",
        "Accept": "application/json"
    };
    
    // 发送带参数的 GET 请求
    var response = http.httpGet(url, params, timeout, headers);
    
    if (response) {
        logd("搜索成功,结果: " + response);
        
        // 解析 JSON 响应
        try {
            var data = JSON.parse(response);
            logd("总记录数: " + data.total);
            logd("当前页数据: " + data.list.length);
            return data;
        } catch (e) {
            loge("JSON 解析失败: " + e);
            return null;
        }
    } else {
        loge("请求失败");
        return null;
    }
}

// 使用示例
getRequestWithParams();

四、POST 请求详解

4.1 表单形式的 POST 请求

javascript 复制代码
/**
 * 发送表单形式的 POST 请求
 * @param url 请求地址
 * @param data 表单数据
 * @param timeout 超时时间
 * @param headers 请求头
 * @return string 响应内容
 */
function postFormRequest() {
    var url = "https://api.example.com/login";
    
    // 表单数据
    var data = {
        "username": "test_user",
        "password": "123456",
        "remember": "true"
    };
    
    var timeout = 10000;
    var headers = {
        "User-Agent": "EasyClick/1.0",
        "Content-Type": "application/x-www-form-urlencoded"
    };
    
    // 发送 POST 请求
    var response = http.httpPost(url, data, null, timeout, headers);
    
    if (response) {
        logd("登录成功,响应: " + response);
        
        // 解析登录结果
        try {
            var result = JSON.parse(response);
            if (result.code === 200) {
                logd("登录成功,Token: " + result.token);
                return result.token;
            } else {
                loge("登录失败: " + result.message);
                return null;
            }
        } catch (e) {
            loge("响应解析失败");
            return null;
        }
    } else {
        loge("登录请求失败");
        return null;
    }
}

// 使用示例
postFormRequest();

4.2 JSON 格式的 POST 请求

javascript 复制代码
/**
 * 发送 JSON 格式的 POST 请求
 * @param url 请求地址
 * @param jsonData JSON 数据对象
 * @param timeout 超时时间
 * @param headers 请求头
 * @return string 响应内容
 */
function postJsonRequest() {
    var url = "https://api.example.com/submit";
    
    // JSON 数据
    var jsonData = {
        "taskId": "TASK_001",
        "status": "completed",
        "result": {
            "successCount": 100,
            "failCount": 5,
            "duration": 3600
        },
        "timestamp": new Date().getTime()
    };
    
    var timeout = 15000;
    var headers = {
        "User-Agent": "EasyClick/1.0",
        "Authorization": "Bearer your_token_here"
    };
    
    // 发送 JSON POST 请求
    var response = http.postJSON(url, jsonData, timeout, headers);
    
    if (response) {
        logd("提交成功: " + response);
        return response;
    } else {
        loge("提交失败");
        return null;
    }
}

// 使用示例
postJsonRequest();

4.3 万能请求函数(推荐)

javascript 复制代码
/**
 * 使用 http.request 发送万能请求
 * 支持 GET/POST/PUT,支持文件上传、自定义 Header、Cookie 等
 */
function universalRequest() {
    var url = "https://api.example.com/upload";
    
    // 构建请求参数
    var params = {
        // 请求地址
        "url": url,
        
        // 请求方法:GET/POST/PUT
        "method": "POST",
        
        // 超时时间(毫秒)
        "timeout": 30000,
        
        // 请求头
        "header": {
            "User-Agent": "EasyClick/1.0",
            "Content-Type": "application/json",
            "Authorization": "Bearer token123"
        },
        
        // Cookie
        "cookie": {
            "sessionId": "abc123",
            "userId": "10086"
        },
        
        // POST 表单数据
        "data": {
            "taskName": "自动化任务",
            "priority": "high"
        },
        
        // 请求体(JSON 字符串)
        "requestBody": JSON.stringify({
            "extraData": "some data"
        }),
        
        // 是否自动跳转
        "followRedirects": true,
        
        // 忽略内容类型检查
        "ignoreContentType": false,
        
        // 忽略 HTTP 错误
        "ignoreHttpErrors": false,
        
        // 最大响应体大小
        "maxBodySize": 10485760, // 10MB
        
        // 代理设置(可选)
        // "proxy": {
        //     "host": "192.168.1.1",
        //     "port": "8080"
        // }
    };
    
    // 发送请求
    var response = http.request(params);
    
    if (response) {
        logd("状态码: " + response.statusCode);
        logd("状态消息: " + response.statusMessage);
        logd("响应头: " + JSON.stringify(response.header));
        logd("Cookie: " + JSON.stringify(response.cookie));
        logd("响应体: " + response.body);
        
        return response;
    } else {
        loge("请求失败");
        return null;
    }
}

// 使用示例
universalRequest();

五、文件上传与下载

5.1 文件上传

javascript 复制代码
/**
 * 上传文件到服务器
 * @param url 上传地址
 * @param filePath 本地文件路径
 * @param extraData 附加表单数据
 * @return string 服务器响应
 */
function uploadFile() {
    var url = "https://api.example.com/upload";
    var filePath = "/sdcard/screenshot.png";
    
    // 检查文件是否存在
    if (!file.exists(filePath)) {
        loge("文件不存在: " + filePath);
        return null;
    }
    
    // 构建文件参数
    var files = {
        "screenshot": filePath  // key 为表单字段名
    };
    
    // 附加表单数据
    var extraData = {
        "taskId": "TASK_001",
        "description": "任务执行截图"
    };
    
    var timeout = 60000; // 上传超时 60 秒
    var headers = {
        "User-Agent": "EasyClick/1.0"
    };
    
    // 发送文件上传请求
    var response = http.httpPost(url, extraData, files, timeout, headers);
    
    if (response) {
        logd("上传成功: " + response);
        
        try {
            var result = JSON.parse(response);
            logd("文件 URL: " + result.fileUrl);
            return result;
        } catch (e) {
            return response;
        }
    } else {
        loge("上传失败");
        return null;
    }
}

// 使用示例
uploadFile();

5.2 多文件上传

javascript 复制代码
/**
 * 同时上传多个文件
 */
function uploadMultipleFiles() {
    var url = "https://api.example.com/batchUpload";
    
    // 多个文件
    var files = {
        "image1": "/sdcard/1.png",
        "image2": "/sdcard/2.png",
        "log": "/sdcard/log.txt"
    };
    
    var data = {
        "batchId": "BATCH_001",
        "totalFiles": "3"
    };
    
    var response = http.httpPost(url, data, files, 120000, {});
    
    if (response) {
        logd("批量上传成功: " + response);
    } else {
        loge("批量上传失败");
    }
}

5.3 文件下载

javascript 复制代码
/**
 * 下载文件到本地
 * @param fileUrl 文件 URL
 * @param savePath 保存路径
 * @param timeout 超时时间
 * @return boolean 是否下载成功
 */
function downloadFile() {
    var fileUrl = "https://example.com/app.apk";
    var savePath = "/sdcard/download/app.apk";
    var timeout = 120000; // 2分钟超时
    
    // 确保下载目录存在
    var dir = file.getParent(savePath);
    if (!file.exists(dir)) {
        file.createDir(dir);
    }
    
    logd("开始下载文件...");
    logd("URL: " + fileUrl);
    logd("保存路径: " + savePath);
    
    // 发送下载请求
    var result = http.downloadFile(
        fileUrl,
        savePath,
        timeout,
        {
            "User-Agent": "EasyClick/1.0"
        }
    );
    
    if (result) {
        logd("下载成功!");
        
        // 检查文件大小
        var fileSize = file.getFileSize(savePath);
        logd("文件大小: " + (fileSize / 1024 / 1024).toFixed(2) + " MB");
        
        return true;
    } else {
        loge("下载失败!");
        return false;
    }
}

// 使用示例
downloadFile();

5.4 简易文件下载

javascript 复制代码
/**
 * 使用默认超时(30秒)下载文件
 */
function quickDownload() {
    var url = "https://example.com/config.json";
    var savePath = "/sdcard/config.json";
    
    var result = http.downloadFileDefault(url, savePath, {});
    
    if (result) {
        logd("下载成功");
        // 读取下载的文件内容
        var content = file.readAllText(savePath);
        logd("文件内容: " + content);
    } else {
        loge("下载失败");
    }
}

六、JSON 数据处理

6.1 JSON 解析与生成

javascript 复制代码
/**
 * JSON 数据处理示例
 */
function jsonHandling() {
    // 1. JSON 字符串转对象(解析)
    var jsonStr = '{"name":"张三","age":25,"skills":["JavaScript","Python"]}';
    var obj = JSON.parse(jsonStr);
    
    logd("姓名: " + obj.name);
    logd("年龄: " + obj.age);
    logd("技能: " + obj.skills.join(", "));
    
    // 2. 对象转 JSON 字符串(生成)
    var data = {
        "taskId": "T001",
        "status": "running",
        "progress": 75.5,
        "details": {
            "startTime": new Date().getTime(),
            "currentStep": 3,
            "totalSteps": 5
        }
    };
    
    var jsonString = JSON.stringify(data);
    logd("JSON 字符串: " + jsonString);
    
    // 3. 格式化输出(带缩进)
    var prettyJson = JSON.stringify(data, null, 2);
    logd("格式化 JSON:\n" + prettyJson);
    
    return data;
}

// 使用示例
jsonHandling();

6.2 处理 API 响应数据

javascript 复制代码
/**
 * 处理 API 返回的 JSON 数据
 */
function handleApiResponse() {
    var url = "https://api.example.com/tasks";
    
    var response = http.httpGetDefault(url, 10000, {});
    
    if (!response) {
        loge("请求失败");
        return null;
    }
    
    try {
        var data = JSON.parse(response);
        
        // 检查响应状态
        if (data.code !== 200) {
            loge("API 错误: " + data.message);
            return null;
        }
        
        // 处理列表数据
        var tasks = data.data.list;
        logd("获取到 " + tasks.length + " 个任务");
        
        for (var i = 0; i < tasks.length; i++) {
            var task = tasks[i];
            logd("任务 " + (i + 1) + ":");
            logd("  ID: " + task.id);
            logd("  名称: " + task.name);
            logd("  状态: " + task.status);
            logd("  创建时间: " + formatTime(task.createTime));
        }
        
        return tasks;
    } catch (e) {
        loge("JSON 解析错误: " + e);
        return null;
    }
}

/**
 * 格式化时间戳
 */
function formatTime(timestamp) {
    var date = new Date(timestamp);
    return date.getFullYear() + "-" + 
           (date.getMonth() + 1) + "-" + 
           date.getDate() + " " + 
           date.getHours() + ":" + 
           date.getMinutes();
}

// 使用示例
handleApiResponse();

七、WebSocket 实时通信

7.1 WebSocket 基础连接

javascript 复制代码
/**
 * WebSocket 客户端示例
 * 用于实时双向通信,如接收服务器推送的任务指令
 */
function websocketExample() {
    var wsUrl = "ws://192.168.1.100:8080/ws/script";
    
    // 创建 WebSocket 连接
    // type: 1 = okhttp3, 2 = javawebsocket
    var ws = http.newWebsocket(wsUrl, null, 2);
    
    // 设置连接参数(type=1 时有效)
    ws.setCallTimeout(5);
    ws.setReadTimeout(5);
    ws.setWriteTimeout(5);
    ws.setPingInterval(0); // 建议设为 0,避免服务端不支持 ping
    
    // 设置连接丢失超时(type=2 时有效)
    ws.setConnectionLostTimeout(5);
    
    // 连接打开回调
    ws.onOpen(function(ws1, code, msg) {
        logi("WebSocket 连接成功!code: " + code);
        
        // 发送登录消息
        ws1.sendText(JSON.stringify({
            "type": "login",
            "deviceId": device.getIMEI(),
            "timestamp": new Date().getTime()
        }));
    });
    
    // 接收文本消息回调
    ws.onText(function(ws1, text) {
        logi("收到消息: " + text);
        
        try {
            var msg = JSON.parse(text);
            
            // 根据消息类型处理
            switch(msg.type) {
                case "task":
                    handleTaskMessage(msg.data);
                    break;
                case "config":
                    updateConfig(msg.data);
                    break;
                case "command":
                    executeCommand(msg.data);
                    break;
                default:
                    logd("未知消息类型: " + msg.type);
            }
        } catch (e) {
            loge("消息解析失败: " + e);
        }
    });
    
    // 连接关闭回调
    ws.onClose(function(ws1, code, reason) {
        logi("WebSocket 连接关闭 code: " + code + " reason: " + reason);
    });
    
    // 错误回调
    ws.onError(function(ws1, msg) {
        loge("WebSocket 错误: " + msg);
    });
    
    // 二进制消息回调
    ws.onBinary(function(ws1, bytes) {
        var text = new java.lang.String(bytes);
        logi("收到二进制消息: " + text);
    });
    
    // 启动心跳(每 30 秒发送一次)
    ws.startHeartBeat(
        function() {
            // 二进制心跳数据(可选)
            return null;
        },
        function() {
            // 文本心跳数据
            return JSON.stringify({
                "type": "heartbeat",
                "time": new Date().toISOString()
            });
        },
        30000, // 心跳间隔 30 秒
        true   // 取消旧的心跳任务
    );
    
    // 启用自动重连
    ws.setAutoReconnect(true);
    
    // 开始连接(阻塞方法)
    logd("正在连接 WebSocket...");
    var connected = ws.connect(10000);
    
    if (connected) {
        logd("WebSocket 连接成功!");
        
        // 保持连接,处理消息
        while (true) {
            sleep(1000);
            
            if (!ws.isConnected()) {
                loge("连接已断开");
                break;
            }
            
            // 可以在这里发送状态报告
            // ws.sendText(JSON.stringify({"type": "status", "progress": 50}));
        }
    } else {
        loge("WebSocket 连接失败!");
    }
    
    // 关闭连接
    ws.close();
    logd("WebSocket 已关闭");
}

/**
 * 处理任务消息
 */
function handleTaskMessage(data) {
    logd("收到任务: " + data.taskName);
    // 执行具体的任务逻辑
}

/**
 * 更新配置
 */
function updateConfig(data) {
    logd("更新配置: " + JSON.stringify(data));
    // 保存配置到本地
}

/**
 * 执行命令
 */
function executeCommand(data) {
    logd("执行命令: " + data.command);
    // 执行系统命令或其他操作
}

// 使用示例
websocketExample();

7.2 WebSocket 工具类封装

javascript 复制代码
/**
 * WebSocket 客户端封装
 */
var WebSocketClient = {
    ws: null,
    reconnectInterval: 5000,
    heartbeatInterval: 30000,
    
    /**
     * 连接到 WebSocket 服务器
     */
    connect: function(url, onMessage) {
        var self = this;
        
        this.ws = http.newWebsocket(url, null, 2);
        this.ws.setConnectionLostTimeout(5);
        this.ws.setAutoReconnect(true);
        
        this.ws.onOpen(function(ws, code, msg) {
            logi("WebSocket 已连接");
        });
        
        this.ws.onText(function(ws, text) {
            if (onMessage) {
                onMessage(text);
            }
        });
        
        this.ws.onClose(function(ws, code, reason) {
            logi("WebSocket 已断开: " + reason);
        });
        
        this.ws.onError(function(ws, msg) {
            loge("WebSocket 错误: " + msg);
        });
        
        // 启动心跳
        this.ws.startHeartBeat(
            function() { return null; },
            function() { 
                return JSON.stringify({"type": "ping", "time": Date.now()}); 
            },
            this.heartbeatInterval,
            true
        );
        
        return this.ws.connect(10000);
    },
    
    /**
     * 发送消息
     */
    send: function(data) {
        if (this.ws && this.ws.isConnected()) {
            var text = typeof data === 'string' ? data : JSON.stringify(data);
            return this.ws.sendText(text);
        }
        return false;
    },
    
    /**
     * 关闭连接
     */
    close: function() {
        if (this.ws) {
            this.ws.stopHeartBeat();
            this.ws.close();
        }
    },
    
    /**
     * 检查连接状态
     */
    isConnected: function() {
        return this.ws && this.ws.isConnected();
    }
};

// 使用示例
function testWebSocketClient() {
    var connected = WebSocketClient.connect(
        "ws://localhost:8080/ws",
        function(msg) {
            logd("收到: " + msg);
        }
    );
    
    if (connected) {
        // 发送消息
        WebSocketClient.send({"type": "hello", "data": "world"});
        
        sleep(5000);
        
        // 关闭连接
        WebSocketClient.close();
    }
}

八、实战案例

案例1:完整的任务上报系统

javascript 复制代码
/**
 * 任务执行结果上报系统
 * 包含:开始执行 -> 进度更新 -> 完成上报
 */
var TaskReporter = {
    apiBaseUrl: "https://api.example.com",
    token: null,
    
    /**
     * 登录获取 Token
     */
    login: function(username, password) {
        var url = this.apiBaseUrl + "/auth/login";
        var data = {
            "username": username,
            "password": password
        };
        
        var response = http.httpPost(url, data, null, 10000, {});
        
        if (response) {
            var result = JSON.parse(response);
            if (result.code === 200) {
                this.token = result.token;
                logd("登录成功,获取到 Token");
                return true;
            }
        }
        
        loge("登录失败");
        return false;
    },
    
    /**
     * 上报任务开始
     */
    reportStart: function(taskId) {
        var url = this.apiBaseUrl + "/task/start";
        var data = {
            "taskId": taskId,
            "deviceId": device.getIMEI(),
            "startTime": new Date().getTime(),
            "status": "running"
        };
        
        var headers = {
            "Authorization": "Bearer " + this.token
        };
        
        var response = http.postJSON(url, data, 10000, headers);
        logd("任务开始上报: " + response);
        return response;
    },
    
    /**
     * 上报任务进度
     */
    reportProgress: function(taskId, progress, message) {
        var url = this.apiBaseUrl + "/task/progress";
        var data = {
            "taskId": taskId,
            "progress": progress,
            "message": message,
            "timestamp": new Date().getTime()
        };
        
        var headers = {
            "Authorization": "Bearer " + this.token
        };
        
        http.postJSON(url, data, 10000, headers);
    },
    
    /**
     * 上报任务完成
     */
    reportComplete: function(taskId, success, result) {
        var url = this.apiBaseUrl + "/task/complete";
        var data = {
            "taskId": taskId,
            "status": success ? "success" : "failed",
            "result": result,
            "endTime": new Date().getTime()
        };
        
        var headers = {
            "Authorization": "Bearer " + this.token
        };
        
        // 如果有截图,一并上传
        var screenshotPath = "/sdcard/task_" + taskId + ".png";
        if (file.exists(screenshotPath)) {
            var files = {"screenshot": screenshotPath};
            var response = http.httpPost(url, data, files, 60000, headers);
            logd("任务完成上报(含截图): " + response);
        } else {
            var response = http.postJSON(url, data, 10000, headers);
            logd("任务完成上报: " + response);
        }
    }
};

/**
 * 使用示例:完整的任务流程
 */
function runTaskWithReport() {
    var taskId = "TASK_" + new Date().getTime();
    
    // 1. 登录
    if (!TaskReporter.login("script_user", "password123")) {
        return;
    }
    
    // 2. 上报任务开始
    TaskReporter.reportStart(taskId);
    
    try {
        // 3. 执行任务(模拟)
        for (var i = 0; i <= 100; i += 10) {
            // 执行具体任务步骤...
            sleep(1000);
            
            // 上报进度
            TaskReporter.reportProgress(taskId, i, "正在执行步骤 " + (i / 10));
        }
        
        // 4. 上报任务完成
        TaskReporter.reportComplete(taskId, true, {"total": 100, "success": 98});
        
    } catch (e) {
        // 上报任务失败
        TaskReporter.reportComplete(taskId, false, {"error": e.message});
    }
}

// 执行
runTaskWithReport();

案例2:自动更新检查与下载

javascript 复制代码
/**
 * 脚本自动更新系统
 */
var AutoUpdater = {
    currentVersion: "1.0.0",
    updateUrl: "https://api.example.com/script/version",
    
    /**
     * 检查更新
     */
    checkUpdate: function() {
        logd("当前版本: " + this.currentVersion);
        logd("正在检查更新...");
        
        var response = http.httpGetDefault(this.updateUrl, 10000, {});
        
        if (!response) {
            loge("检查更新失败");
            return null;
        }
        
        try {
            var data = JSON.parse(response);
            
            if (data.version !== this.currentVersion) {
                logd("发现新版本: " + data.version);
                logd("更新内容: " + data.changelog);
                return data;
            } else {
                logd("当前已是最新版本");
                return null;
            }
        } catch (e) {
            loge("解析更新信息失败");
            return null;
        }
    },
    
    /**
     * 下载并安装更新
     */
    downloadAndInstall: function(updateInfo) {
        var savePath = "/sdcard/download/script_update.zip";
        
        logd("开始下载更新包...");
        
        var result = http.downloadFile(
            updateInfo.downloadUrl,
            savePath,
            120000,
            {}
        );
        
        if (result) {
            logd("下载完成,保存路径: " + savePath);
            
            // 校验文件 MD5
            var fileMd5 = utils.fileMd5(savePath);
            if (fileMd5 === updateInfo.md5) {
                logd("文件校验通过");
                
                // 解压更新包
                // ... 解压逻辑
                
                logd("更新完成,请重启脚本");
                return true;
            } else {
                loge("文件校验失败");
                return false;
            }
        } else {
            loge("下载失败");
            return false;
        }
    }
};

// 使用示例
function checkAndUpdate() {
    var updateInfo = AutoUpdater.checkUpdate();
    
    if (updateInfo) {
        // 提示用户是否更新
        var confirm = confirmDialog("发现新版本 " + updateInfo.version + ",是否更新?\n\n更新内容:\n" + updateInfo.changelog);
        
        if (confirm) {
            AutoUpdater.downloadAndInstall(updateInfo);
        }
    }
}

案例3:对接第三方打码平台

javascript 复制代码
/**
 * 对接打码平台识别验证码
 */
var CaptchaSolver = {
    apiUrl: "http://api.captcha.com/recognize",
    apiKey: "your_api_key_here",
    
    /**
     * 识别图片验证码
     * @param imagePath 图片路径
     * @return string 识别结果
     */
    solve: function(imagePath) {
        if (!file.exists(imagePath)) {
            loge("图片不存在: " + imagePath);
            return null;
        }
        
        var url = this.apiUrl;
        var data = {
            "apiKey": this.apiKey,
            "type": "image"
        };
        var files = {
            "image": imagePath
        };
        
        logd("正在识别验证码...");
        
        var response = http.httpPost(url, data, files, 30000, {});
        
        if (response) {
            try {
                var result = JSON.parse(response);
                
                if (result.code === 200) {
                    logd("识别成功: " + result.text);
                    return result.text;
                } else {
                    loge("识别失败: " + result.message);
                    return null;
                }
            } catch (e) {
                loge("响应解析失败");
                return null;
            }
        } else {
            loge("请求失败");
            return null;
        }
    }
};

// 使用示例
function autoLoginWithCaptcha() {
    // 1. 截图获取验证码
    var captchaPath = "/sdcard/captcha.png";
    captureScreen(captchaPath);
    
    // 2. 识别验证码
    var captchaText = CaptchaSolver.solve(captchaPath);
    
    if (captchaText) {
        // 3. 输入验证码并登录
        inputText(captchaText);
        clickLoginButton();
    }
}

九、常见问题

Q1: 请求超时怎么办?

javascript 复制代码
// 增加超时时间
var response = http.httpGetDefault(url, 30000, {}); // 30秒超时

// 或者使用重试机制
function requestWithRetry(url, maxRetry) {
    for (var i = 0; i < maxRetry; i++) {
        var response = http.httpGetDefault(url, 10000, {});
        if (response) {
            return response;
        }
        logd("第 " + (i + 1) + " 次请求失败,准备重试...");
        sleep(2000);
    }
    return null;
}

Q2: 如何处理 HTTPS 证书错误?

javascript 复制代码
// 使用万能请求,设置忽略证书错误
var params = {
    "url": "https://self-signed.badssl.com/",
    "method": "GET",
    "timeout": 10000,
    "ignoreHttpErrors": true,  // 忽略 HTTP 错误
    "header": {
        "User-Agent": "EasyClick/1.0"
    }
};

var response = http.request(params);

Q3: 中文乱码怎么处理?

javascript 复制代码
// 设置响应字符集
var params = {
    "url": url,
    "method": "GET",
    "responseCharset": "UTF-8"  // 强制使用 UTF-8 编码
};

var response = http.request(params);

Q4: 如何设置代理?

javascript 复制代码
var params = {
    "url": url,
    "method": "GET",
    "proxy": {
        "host": "192.168.1.100",
        "port": "8080"
    }
};

var response = http.request(params);

Q5: WebSocket 连接断开如何自动重连?

javascript 复制代码
// 设置自动重连
ws.setAutoReconnect(true);

// 或者在 onClose 回调中手动重连
ws.onClose(function(ws1, code, reason) {
    logi("连接断开,准备重连...");
    sleep(5000);
    ws1.connect(10000);
});

结语

通过本文,你应该已经掌握了 EasyClick 中 HTTP 网络请求的各种用法:

  • GET/POST 请求的发送
  • 文件上传和下载
  • JSON 数据的处理
  • WebSocket 实时通信
  • 与第三方 API 的对接

建议:

  • 网络请求需要处理超时和重试机制
  • 敏感信息(Token、密码)不要硬编码
  • 文件上传下载注意检查存储权限
  • WebSocket 注意心跳保活和断线重连

相关资源:

相关推荐
tedcloud1231 小时前
Supermemory部署教程:打造Agent记忆与RAG环境
服务器·人工智能·学习·自动化·powerpoint
工业机器人销售服务1 小时前
伯朗特冷轧钢板自动上下料,无痕平稳取放,适配精密钣金加工产线
机器人·自动化
IPDEEP全球代理1 小时前
静态住宅ip哪家好?2026年静态住宅ip测评
运维·服务器·网络
上海云盾第一敬业销售1 小时前
WAF架构解析与实战经验分享
网络协议·web安全·架构
PixelBai1 小时前
JSON差异比较集成指南与工作流自动化
运维·自动化·json
feasibility.2 小时前
摆脱专利撰写内耗!OpenCode/Hermes 自动产出专利交底书(含安装和演示)
科技·自动化·专利·skills·opencode·hermes·爱马仕
liulilittle2 小时前
删除 Inflight Bounds:为什么 KCC 放弃了 BDP 钳位
linux·网络·tcp/ip·计算机网络·信息与通信·tcp·通信
云飞云共享云桌面2 小时前
面向机械研发:双服务器架构搭配云飞云运行 SolidWorks 方案详解
运维·服务器·前端·网络·架构·制造
吕工-老船长19982 小时前
20260610----S905Y5(Android14)-----连接WiFi成功后显示网络受限或者开机不会回连
网络