树莓派Pico W HTTP服务器响应异常:Wget提示"No headers"如何修复?
修复Raspberry Pi Pico W的HTTP响应格式,兼容多客户端解析
问题现象
在Raspberry Pi Pico W上运行HTTP服务器时,响应无法被多客户端正确解析:
- Chrome可解析响应头,但Firefox无法解析
- cURL和Python Requests判定无HTTP头,直接关闭连接
- Wget将响应头当作响应体处理,提示
No headers, assuming HTTP/0.9 - cURL提示
Received HTTP/0.9 when not allowed
问题代码片段
原使用ArduinoHttpClient库处理服务器请求的代码:
WiFiServer server(80); // server on port 80 void loop(){ WiFiClient wificlient = server.available(); // Listen for incoming clients // If a new client connects, if (wificlient) { HttpClient client(wificlient, WiFi.localIP()); net_time = millis(); net_prev_time = net_time; while ((client.connected() || client.available()) && (!client.endOfBodyReached()) && (net_time - net_prev_time <= net_timeout)) { net_time = millis(); if (client.available()) { char c = client.read(); // read a byte Serial.write(c); httpbody += c; if (!client.available()) { // client is done, respond if (httpbody.indexOf("GET /api/last") == 0){ Serial.println("Serving api request..."); client.println("HTTP/1.1 200 OK"); client.println("Content-type: text/plain; charset=utf-8"); client.println("Content-length: " + String(last_str.length())); client.println("Content-Disposition: inline"); client.println("Connection: close"); client.println(""); client.println(last_str); client.println(""); break; } } } ... }
问题根源
- 误用ArduinoHttpClient库:该库是用于发起HTTP请求的客户端工具,并非处理服务器端请求的库,会干扰原始请求的读取和响应发送逻辑。
- 请求结束判断逻辑错误:用
!client.available()判定请求完成不可靠,HTTP请求头的结束标志是\r\n\r\n(空行),必须读取到该标志才能确认请求接收完成,否则会提前发送响应。 - 响应换行不符合HTTP规范:HTTP协议要求所有头字段之间、头与正文之间必须用
\r\n(回车+换行)分隔,而client.println()默认只输出\n,导致客户端无法识别响应头的结束位置。
修复方案
1. 移除HttpClient,直接使用WiFiClient处理
服务器端仅需用WiFiClient读取请求和发送响应,无需引入HttpClient库。
2. 正确读取HTTP请求直到结束标志
循环读取请求数据,直到遇到\r\n\r\n,确认请求接收完成。
3. 用\r\n作为响应的换行符
手动拼接包含\r\n的响应内容,或使用client.print()配合\r\n发送,确保符合HTTP规范。
修改后的代码示例
WiFiServer server(80); String httpRequest; void loop() { WiFiClient client = server.available(); if (client) { Serial.println("New client connected"); httpRequest = ""; unsigned long timeout = millis(); // 读取请求直到空行或超时 while (client.connected() && millis() - timeout <= 5000) { if (client.available()) { char c = client.read(); httpRequest += c; timeout = millis(); // 检查HTTP请求结束标志:\r\n\r\n if (httpRequest.endsWith("\r\n\r\n")) { break; } } } // 处理/api/last请求 if (httpRequest.indexOf("GET /api/last") != -1) { Serial.println("Serving /api/last request"); // 发送符合HTTP规范的响应,用\r\n分隔 client.print("HTTP/1.1 200 OK\r\n"); client.print("Content-Type: text/plain; charset=utf-8\r\n"); client.print("Content-Length: " + String(last_str.length()) + "\r\n"); client.print("Connection: close\r\n"); // 空行分隔响应头与正文 client.print("\r\n"); // 发送响应正文 client.print(last_str); } else { // 处理其他请求,返回404 client.print("HTTP/1.1 404 Not Found\r\n"); client.print("Connection: close\r\n"); client.print("\r\n"); client.print("404 Not Found"); } // 等待数据发送完成后关闭连接 delay(10); client.stop(); Serial.println("Client disconnected"); } }
关键修改说明
- 移除HttpClient依赖:直接用WiFiClient处理,避免库逻辑干扰服务器端请求响应流程。
- 规范请求结束判断:通过
httpRequest.endsWith("\r\n\r\n")识别HTTP请求头的结束,符合协议规定。 - 响应格式标准化:所有响应头字段末尾用
\r\n,头与正文之间用单独的\r\n分隔,确保客户端能正确识别响应结构。 - 添加超时处理:防止客户端连接后不发送请求导致服务器无限等待。
内容的提问来源于stack exchange,提问作者zeitoon
相关产品推荐
相关产品推荐

