Android中OkHttp3获取图片文件而非HTML响应的技术求助
问题分析
你遇到的是免费主机(infinityfree)的人机验证/防盗链机制:首次请求会返回一段JS脚本,用于设置_test Cookie并自动重定向到带i=1参数的真实下载地址。浏览器会自动执行JS完成Cookie设置和跳转,但OkHttp不会解析执行JS,因此直接请求会拿到这段HTML而非文件数据。同时你的Java代码用string()读取二进制文件的方式也错误,会破坏文件内容。
解决方案
一、修改OkHttp代码(核心解决步骤)
需要手动解析首次响应中的Cookie和重定向URL,带上Cookie发起第二次请求,同时用正确方式读取二进制文件:
OkHttpClient client = new OkHttpClient.Builder() .followRedirects(true) .build(); // 1. 发起首次请求,获取验证Cookie和重定向地址 String initialUrl = "http://www.webweb.infinityfreeapp.com/lichi/download.php?path=Add.jpg"; Request initialReq = new Request.Builder().url(initialUrl).get().build(); Response initialResp = client.newCall(initialReq).execute(); if (initialResp.isSuccessful()) { String htmlContent = initialResp.body().string(); // 解析_test Cookie值 String testCookie = null; Pattern cookiePattern = Pattern.compile("_test=([a-f0-9]+)"); Matcher cookieMatcher = cookiePattern.matcher(htmlContent); if (cookieMatcher.find()) { testCookie = cookieMatcher.group(1); } // 解析重定向URL String redirectUrl = null; Pattern redirectPattern = Pattern.compile("document\\.location\\.href=\"(.*?)\""); Matcher redirectMatcher = redirectPattern.matcher(htmlContent); if (redirectMatcher.find()) { redirectUrl = redirectMatcher.group(1); } // 2. 带上Cookie发起真实下载请求 if (testCookie != null && redirectUrl != null) { Request downloadReq = new Request.Builder() .url(redirectUrl) .addHeader("Cookie", "_test=" + testCookie) .get() .build(); Response downloadResp = client.newCall(downloadReq).execute(); if (downloadResp.isSuccessful()) { // 用bytes()读取二进制文件,不要用string() byte[] fileData = downloadResp.body().bytes(); // 这里添加文件保存逻辑,比如写入本地存储 Log.d(LOG_TAG, "文件下载成功,大小:" + fileData.length); } } }
二、优化PHP代码(辅助规范响应)
你的PHP代码存在MIME类型错误、文件路径不合理的问题,优化后能让响应更规范,避免潜在问题:
if(isset($_GET['path'])) { $fileName = $_GET['path']; $localFilePath = __DIR__ . '/' . $fileName; // 使用本地路径代替远程URL,避免allow_url_fopen限制 // 验证文件存在性 if(!file_exists($localFilePath)){ http_response_code(404); die("文件不存在"); } // 根据文件后缀设置正确的MIME类型 $fileExt = pathinfo($fileName, PATHINFO_EXTENSION); $mimeTypes = [ 'jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'png' => 'image/png', 'pdf' => 'application/pdf' ]; $contentType = isset($mimeTypes[$fileExt]) ? $mimeTypes[$fileExt] : 'application/octet-stream'; // 输出下载响应头 header("Content-disposition: attachment; filename=" . basename($fileName)); header("Content-Type: $contentType"); header("Content-Transfer-Encoding: binary"); header("Pragma: no-cache"); header("Cache-Control: must-revalidate, post-check=0, pre-check=0, public"); header("Expires: 0"); header("Content-Length: " . filesize($localFilePath)); // 本地文件可正常获取大小 readfile($localFilePath); die(); }
内容的提问来源于stack exchange,提问作者Hitlar India
相关产品推荐
相关产品推荐

