Android请求PHP接口返回HTML而非JSON,如何获取正确JSON?
我来帮你拆解下当前遇到的问题——你明明在PHP端设置了Content-Type: application/json并输出JSON,但Android端拿到的却是带AES解密JS和noscript提示的HTML,这大概率是服务器的客户端验证/反爬机制在拦截你的请求,甚至可能在请求到达你的PHP代码之前就被拦截了。下面是具体的排查和解决步骤:
1. 先给请求换上“浏览器身份”(重点!)
默认的HttpURLConnection会用Dalvik相关的User-Agent标识自己,很容易被服务器识别为非浏览器请求,触发验证页面。你需要把User-Agent改成主流移动端浏览器的标识,比如Chrome移动端的:
URL url = new URL("https://example.net/index.php"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); // 设置和真实Chrome移动端一致的User-Agent conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Linux; Android 10; SM-G973F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.36"); // 明确告诉服务器我们只接收JSON conn.setRequestProperty("Accept", "application/json"); conn.setRequestMethod("GET");
2. 处理会话Cookie(如果服务器要求)
有些服务器会在第一次请求时下发会话Cookie,只有后续请求带上这个Cookie,才会跳过验证直接返回数据。你可以先发起一次请求拿到Cookie,再带着Cookie发起第二次请求:
// 第一次请求获取Cookie String sessionCookie = conn.getHeaderField("Set-Cookie"); conn.disconnect(); // 第二次请求带上Cookie HttpURLConnection validConn = (HttpURLConnection) url.openConnection(); validConn.setRequestProperty("Cookie", sessionCookie); validConn.setRequestProperty("User-Agent", "上面的Chrome标识"); validConn.setRequestProperty("Accept", "application/json"); // 后续读取响应...
3. 检查PHP端是否藏了验证逻辑
虽然你说PHP已经输出JSON,但可能代码里有隐藏的条件判断——比如只有满足特定请求头的请求才会返回JSON,否则跳转到验证页面。举个常见的例子:
// PHP里可能存在这样的判断 if (!isset($_SERVER['HTTP_USER_AGENT']) || strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome') === false) { // 返回带AES解密的验证页面 include 'verify_page.html'; exit; } // 验证通过才输出JSON header('Content-Type: application/json'); echo json_encode(['status' => 'success', 'data' => 'xxx']);
如果是这种情况,你需要确保Android端的请求完全符合PHP的验证条件。
4. 模拟更完整的浏览器请求环境
除了User-Agent和Cookie,还可以添加一些浏览器常用的请求头,让你的请求更“真实”:
conn.setRequestProperty("Accept-Language", "zh-CN,zh;q=0.9"); conn.setRequestProperty("Referer", "https://example.net/"); // 如果接口要求Referer conn.setRequestProperty("Connection", "keep-alive");
5. 排查CDN/反向代理的拦截
如果你的服务器前面挂了CDN(比如Cloudflare)或者反向代理,它们可能会先做一层人机验证,只有通过验证的请求才会转发到你的PHP后端。这种情况下:
- 先检查CDN的规则,是否把Android端请求误判为爬虫
- 如果是Cloudflare的Turnstile验证,原生Android处理起来比较麻烦,你可以先用WebView加载一次验证页面,获取通过验证后的Cookie,再用
HttpURLConnection带着Cookie请求接口
快速测试建议
你可以先用curl或者Postman模拟Android端的请求,看看能不能拿到JSON。比如用curl命令:
curl -H "User-Agent: Mozilla/5.0 (Linux; Android 10; SM-G973F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.36" -H "Accept: application/json" https://example.net/index.php
如果curl能拿到JSON,说明问题在Android端的请求头设置;如果curl也返回HTML,那肯定是服务器端(CDN或PHP逻辑)的问题。
内容的提问来源于stack exchange,提问作者blackJack

