Android中转换PHP响应字符串为JSON时持续提示格式错误
解决Volley解析PHP返回JSON报格式错误的问题
这种情况我碰到过好多次,看起来在线解析正常但Android报错,大概率是响应里藏了看不见的特殊字符或者PHP输出时的细节没处理到位,给你一步步排查的思路和解决办法:
1. 先排查PHP输出的“隐形问题”
很多时候你肉眼看不到的字符会搞砸JSON解析:
- UTF-8 BOM头:如果你的PHP文件是UTF-8带BOM格式,开头会有
EF BB BF三个隐藏字符,在线解析器会自动忽略,但Android的JSON解析器会把它当成JSON的一部分,直接报错。
解决:用编辑器把PHP文件转成UTF-8无BOM格式(比如VS Code右下角选编码,再选“通过编码保存”→UTF-8无BOM)。 - 额外输出字符:PHP文件开头
<?php前的空格、换行,或者结尾?>后的空白,都会被当成响应内容输出。
解决:删掉PHP文件结尾的?>(完全可以不用写),同时确保<?php前没有任何字符;输出JSON前先清空缓冲区:ob_clean(); // 清空之前的输出 header('Content-Type: application/json; charset=utf-8'); echo json_encode($your_data); exit; // 确保后面没有额外输出
2. 确保PHP返回正确的响应头
Volley对响应头很敏感,如果没明确告诉客户端这是JSON数据,可能触发解析异常:
// 一定要在输出JSON前设置这个头 header('Content-Type: application/json; charset=utf-8');
3. 清理MSSQL返回的特殊字符
MSSQL里的字符串可能带有控制字符(比如换行、制表符、不可见的ASCII控制码),这些在线解析器能容忍,但Android的JSON解析器会判定为格式错误:
// 遍历查询结果,清理每个字符串字段 while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_ASSOC) ) { $clean_row = array_map(function($val) { if(is_string($val)) { // 去掉首尾空白+清理控制字符 return preg_replace('/[\x00-\x1F\x7F]/u', '', trim($val)); } return $val; }, $row); $data[] = $clean_row; }
4. 在Android端抓包验证原始响应
有时候你复制的响应和Volley实际收到的不一样,建议:
- 用Android Studio的Network Inspector抓包,看原始响应的十六进制内容,检查开头有没有BOM头或其他奇怪字符;
- 用
StringRequest先拿到原始字符串,打印出来再手动解析,顺便做清理:
StringRequest request = new StringRequest(Request.Method.GET, url, response -> { // 去掉可能的BOM头 response = response.replace("\uFEFF", ""); try { JSONObject json = new JSONObject(response); JSONArray data = json.getJSONArray("data"); // 处理数据... } catch (JSONException e) { Log.e("JSON_ERROR", "解析失败: " + e.getMessage() + "\n原始响应: " + response); } }, error -> { // 处理错误... } ); Volley.newRequestQueue(context).add(request);
完整PHP示例代码
<?php ob_clean(); header('Content-Type: application/json; charset=utf-8'); // 连接MSSQL $serverName = "你的服务器地址"; $connectionInfo = array( "Database"=>"你的数据库", "UID"=>"用户名", "PWD"=>"密码"); $conn = sqlsrv_connect( $serverName, $connectionInfo); if( $conn === false ) { echo json_encode(["error" => "连接失败: " . print_r(sqlsrv_errors(), true)]); exit; } // 查询数据 $sql = "SELECT claimNumber FROM 你的表名"; $stmt = sqlsrv_query( $conn, $sql ); if( $stmt === false) { echo json_encode(["error" => "查询失败: " . print_r(sqlsrv_errors(), true)]); exit; } // 处理并清理数据 $data = []; while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_ASSOC) ) { $cleanRow = array_map(function($val) { if(is_string($val)) { return preg_replace('/[\x00-\x1F\x7F]/u', '', trim($val)); } return $val; }, $row); $data[] = $cleanRow; } sqlsrv_free_stmt( $stmt); sqlsrv_close( $conn); // 输出JSON echo json_encode(["data" => $data], JSON_UNESCAPED_UNICODE); exit; ?>
内容的提问来源于stack exchange,提问作者Richard Maring
相关产品推荐
相关产品推荐

