在使用Ajax进行前后端数据交互的过程中,部分开发者会遇到返回结果中夹杂无意义异常字符的情况,这类问题大多和HTTP协议中的分块传输编码机制相关。要彻底解决这类问题,需要先理解分块传输编码的工作逻辑,再针对性调整数据处理方式。

什么是HTTP分块传输编码
HTTP分块传输编码是HTTP/1.1协议支持的一种数据传输方式,当服务端无法确定响应内容的总长度时,会将数据分割成多个大小不等的块依次发送给客户端,每个块前面会标注当前块的长度,最后一个块长度为0表示传输结束。这种机制不需要在响应头中设置Content-Length字段,适合动态生成内容的场景,比如大文件下载、流式数据返回等。
异常字符产生的常见原因
分块传输本身不会引入异常字符,问题大多出现在客户端对分块数据的解析过程中,常见原因有以下几点:
- 前端收到分块数据后没有正确拼接,直接把分块的长度标识、分隔符等元数据当作业务数据使用
- 后端在分块传输时额外添加了自定义的分隔符,前端没有做对应的过滤处理
- 数据编码格式不一致,比如后端用UTF-8编码传输,前端用GBK解析,导致字符乱码
- Ajax请求没有正确设置响应类型,浏览器对二进制分块数据做了错误的字符串转换
解决方案与代码示例
前端处理方案
原生XMLHttpRequest和fetch API都内置了分块传输的解析能力,不需要手动处理分块的长度标识,只需要保证正确拼接数据即可。以下是原生的Ajax请求示例:
// 原生Ajax处理分块传输数据
const xhr = new XMLHttpRequest();
xhr.open('GET', '/api/chunk-data');
// 如果返回的是JSON数据,设置响应类型为text,避免浏览器自动解析
xhr.responseType = 'text';
let result = '';
xhr.onreadystatechange = function() {
if (xhr.readyState === 3) {
// 接收过程中的数据,逐步拼接
result += xhr.responseText.substring(result.length);
}
if (xhr.readyState === 4) {
// 传输完成,处理完整数据
try {
const data = JSON.parse(result);
console.log('解析后的数据:', data);
} catch (e) {
console.error('数据解析失败,原始内容:', result);
}
}
};
xhr.send();如果使用fetch API,可以通过读取响应流的方式处理分块数据:
// fetch API处理分块传输数据
fetch('/api/chunk-data')
.then(response => {
const reader = response.body.getReader();
const decoder = new TextDecoder('utf-8');
let fullResult = '';
// 递归读取流数据
function readChunk() {
return reader.read().then(({ done, value }) => {
if (done) {
// 所有数据读取完成
try {
const data = JSON.parse(fullResult);
console.log('解析后的数据:', data);
} catch (e) {
console.error('数据解析失败,原始内容:', fullResult);
}
return;
}
// 解码当前块的数据并拼接
fullResult += decoder.decode(value, { stream: true });
return readChunk();
});
}
return readChunk();
})
.catch(err => console.error('请求失败:', err));后端处理方案
后端如果需要使用分块传输返回数据,要保证只返回业务数据内容,不要额外添加自定义的分隔符。以下是Node.js Express框架的示例:
const express = require('express');
const app = express();
app.get('/api/chunk-data', (req, res) => {
// 设置分块传输的响应头,不需要设置Content-Length
res.setHeader('Transfer-Encoding', 'chunked');
res.setHeader('Content-Type', 'application/json; charset=utf-8');
// 分块返回数据,每块都是合法的业务数据片段
res.write(JSON.stringify({ part: 1, data: '第一批数据' }));
// 模拟异步分块返回
setTimeout(() => {
res.write(JSON.stringify({ part: 2, data: '第二批数据' }));
// 传输结束,关闭连接
res.end();
}, 1000);
});
app.listen(3000, () => {
console.log('服务启动在3000端口');
});如果使用Java Spring Boot,可以通过StreamingResponseBody实现分块传输:
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
import java.io.IOException;
import java.io.OutputStream;
@RestController
public class ChunkController {
@GetMapping(value = "/api/chunk-data", produces = MediaType.APPLICATION_JSON_VALUE)
public StreamingResponseBody getChunkData() {
return new StreamingResponseBody() {
@Override
public void writeTo(OutputStream outputStream) throws IOException {
// 第一块数据
String chunk1 = "{\"part\":1,\"data\":\"第一批数据\"}";
outputStream.write(chunk1.getBytes("UTF-8"));
outputStream.flush();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// 第二块数据
String chunk2 = "{\"part\":2,\"data\":\"第二批数据\"}";
outputStream.write(chunk2.getBytes("UTF-8"));
outputStream.flush();
}
};
}
}注意事项
- 如果业务场景不需要分块传输,尽量在后端设置明确的
Content-Length,避免触发分块传输机制 - 前端处理数据时要先校验数据格式,避免直接解析不完整的分块数据
- 前后端要统一字符编码,推荐使用UTF-8编码传输所有文本数据
- 如果返回的是二进制数据,前端要设置
responseType为arraybuffer或者blob,不要直接当作字符串处理
AjaxHTTP_分块传输编码异常字符处理前后端交互修改时间:2026-06-05 16:06:43