Files
HouseProperty/服务器响应警告问题分析.txt

316 lines
9.0 KiB
Plaintext
Raw Normal View History

2026-01-09 16:09:42 +08:00
# 服务器响应警告问题分析
## 问题描述
从日志中可以看到API响应中混入了PHP警告信息
```
<br />
<b>Warning</b>: fopen(/var/www/wy/log.dat): failed to open stream: No such file or directory in <b>/home/renjianbo/saars/wy/wy/wy/server/application/Interface/libraries/Api/Goods/AddGoodsInfo.php</b> on line <b>85</b><br />
<br />
<b>Warning</b>: fwrite() expects parameter 1 to be resource, bool given in <b>/home/renjianbo/saars/wy/wy/wy/server/application/Interface/libraries/Api/Goods/AddGoodsInfo.php</b> on line <b>86</b><br />
<br />
<b>Warning</b>: fclose() expects parameter 1 to be resource, bool given in <b>/home/renjianbo/saars/wy/wy/wy/server/application/Interface/libraries/Api/Goods/AddGoodsInfo.php</b> on line <b>87</b><br />
{
"status": 0,
"msg": "添加成功",
"data": {...}
}
```
## 问题原因
### 服务器端问题
1. **日志文件路径不存在**
- 服务器尝试打开日志文件:`/var/www/wy/log.dat`
- 文件或目录不存在,导致 `fopen()` 返回 `false`
2. **错误处理不当**
- PHP代码没有检查 `fopen()` 的返回值
- 直接对 `false` 值调用 `fwrite()` 和 `fclose()`
- PHP警告被输出到HTTP响应中
3. **错误输出配置**
- PHP的 `display_errors` 可能被设置为 `On`
- 导致警告信息输出到响应体中
### 影响分析
#### ✅ 当前状态
- **业务功能正常**虽然响应中有警告但JSON数据仍然成功解析
- **状态码正确**`status: 0` 表示操作成功
- **数据完整**`data` 字段包含完整的业务数据
#### ⚠️ 潜在风险
1. **JSON解析失败风险**
- 如果警告信息在JSON之前可能导致Gson解析失败
- 某些严格的JSON解析器可能无法处理混入HTML的响应
2. **响应体污染**
- 响应体包含非JSON内容增加解析复杂度
- 可能在某些情况下导致解析异常
3. **日志记录失败**
- 服务器端日志无法正常记录
- 影响问题排查和监控
## 解决方案
### 方案一:服务器端修复(推荐)
#### 1. 修复日志文件路径
在服务器端 `AddGoodsInfo.php` 文件中:
```php
// 修改前第85行
$logFile = fopen('/var/www/wy/log.dat', 'a');
// 修改后
$logDir = '/var/www/wy/';
$logFile = $logDir . 'log.dat';
// 确保目录存在
if (!is_dir($logDir)) {
mkdir($logDir, 0755, true);
}
// 检查文件是否可写
$handle = @fopen($logFile, 'a');
if ($handle === false) {
// 记录到系统日志或使用error_log
error_log("无法打开日志文件: $logFile");
// 不输出警告到响应
} else {
// 正常写入日志
fwrite($handle, $logContent);
fclose($handle);
}
```
#### 2. 关闭错误输出
在PHP配置或代码中
```php
// 关闭错误显示(生产环境)
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', '/var/log/php_errors.log');
```
#### 3. 使用异常处理
```php
try {
$logFile = fopen('/var/www/wy/log.dat', 'a');
if ($logFile === false) {
throw new Exception('无法打开日志文件');
}
fwrite($logFile, $logContent);
fclose($logFile);
} catch (Exception $e) {
// 记录到系统日志,不输出到响应
error_log($e->getMessage());
}
```
### 方案二:客户端容错处理(临时方案)
如果暂时无法修改服务器端,可以在客户端添加响应清理:
#### 1. 创建自定义Gson Converter
创建文件:`app/src/main/java/http/CleanResponseConverter.java`
```java
package http;
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import okhttp3.ResponseBody;
import retrofit2.Converter;
import java.io.IOException;
import java.nio.charset.Charset;
import okio.Buffer;
import okio.BufferedSource;
public class CleanResponseConverter<T> implements Converter<ResponseBody, T> {
private final Gson gson;
private final TypeAdapter<T> adapter;
CleanResponseConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}
@Override
public T convert(ResponseBody value) throws IOException {
BufferedSource bufferedSource = value.source();
bufferedSource.request(Long.MAX_VALUE);
Buffer buffer = bufferedSource.buffer();
String responseString = buffer.clone().readString(Charset.forName("UTF-8"));
// 清理PHP警告和HTML标签
responseString = cleanResponse(responseString);
try {
return adapter.fromJson(responseString);
} finally {
value.close();
}
}
/**
* 清理响应中的PHP警告和HTML标签
*/
private String cleanResponse(String response) {
if (response == null) {
return "";
}
// 移除PHP警告<br />和<b>Warning</b>标签)
response = response.replaceAll("<br\\s*/?>", "");
response = response.replaceAll("<b>Warning</b>", "");
response = response.replaceAll("</b>", "");
response = response.replaceAll("<b>", "");
// 查找JSON开始位置第一个{或[
int jsonStart = -1;
for (int i = 0; i < response.length(); i++) {
char c = response.charAt(i);
if (c == '{' || c == '[') {
jsonStart = i;
break;
}
}
// 如果找到JSON开始位置只保留JSON部分
if (jsonStart > 0) {
response = response.substring(jsonStart);
}
// 移除JSON结束后的所有内容
int jsonEnd = response.lastIndexOf('}');
if (jsonEnd > 0 && response.trim().endsWith("}")) {
// JSON以}结尾,保留
} else if (jsonEnd > 0) {
response = response.substring(0, jsonEnd + 1);
}
return response.trim();
}
}
```
#### 2. 创建Converter Factory
创建文件:`app/src/main/java/http/CleanResponseConverterFactory.java`
```java
package http;
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.reflect.TypeToken;
import retrofit2.Converter;
import retrofit2.Converter.Factory;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
public class CleanResponseConverterFactory extends Factory {
private final Gson gson;
public CleanResponseConverterFactory(Gson gson) {
this.gson = gson;
}
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, retrofit2.Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new CleanResponseConverter<>(gson, (TypeAdapter<Object>) adapter);
}
}
```
#### 3. 修改RetrofitServiceManager
在 `app/src/main/java/http/RetrofitServiceManager.java` 中:
```java
// 修改前
.addConverterFactory(GsonConverterFactory.create())
// 修改后
.addConverterFactory(new CleanResponseConverterFactory(new Gson()))
```
## 问题定位
### 服务器端文件位置
- **文件路径**: `/home/renjianbo/saars/wy/wy/wy/server/application/Interface/libraries/Api/Goods/AddGoodsInfo.php`
- **问题行数**: 第85-87行
### 相关API接口
- **接口**: `AddGoodsInfo` (添加商品信息)
- **请求URL**: `http://101.43.95.130:8030/api/`
- **请求参数**:
- `app`: "Goods"
- `class`: "AddGoodsInfo"
- `sign`: MD5签名
## 测试验证
### 验证服务器端修复
1. 检查日志文件是否存在:`ls -la /var/www/wy/log.dat`
2. 检查目录权限:`ls -ld /var/www/wy/`
3. 测试API响应是否干净无PHP警告
### 验证客户端修复
1. 查看日志中响应体是否包含警告
2. 确认JSON解析是否正常
3. 测试业务功能是否正常
## 建议优先级
### 🔴 高优先级(立即处理)
1. **服务器端修复日志文件路径问题**
- 创建目录或修复路径
- 添加错误检查
2. **关闭PHP错误输出到响应**
- 设置 `display_errors = 0`
- 使用 `error_log` 记录错误
### 🟡 中优先级(短期处理)
1. **添加客户端响应清理**
- 实现自定义Converter
- 清理响应中的HTML标签
2. **完善错误处理机制**
- 添加响应验证
- 添加异常处理
### 🟢 低优先级(长期优化)
1. **统一日志记录机制**
- 使用统一的日志服务
- 添加日志轮转
2. **API响应标准化**
- 确保所有API响应格式统一
- 添加响应验证
## 总结
当前问题虽然不影响业务功能,但存在潜在风险。建议:
1. **优先修复服务器端**:从根本上解决问题
2. **客户端添加容错**:作为临时保护措施
3. **完善监控机制**:及时发现类似问题
---
**问题发现时间**: 2026-01-09 15:40:30
**影响范围**: AddGoodsInfo API接口
**严重程度**: 中等(功能正常,但响应格式不规范)