You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派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;
         }
       }
    }
...
}

问题根源

  1. 误用ArduinoHttpClient库:该库是用于发起HTTP请求的客户端工具,并非处理服务器端请求的库,会干扰原始请求的读取和响应发送逻辑。
  2. 请求结束判断逻辑错误:用!client.available()判定请求完成不可靠,HTTP请求头的结束标志是\r\n\r\n(空行),必须读取到该标志才能确认请求接收完成,否则会提前发送响应。
  3. 响应换行不符合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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 02:39:56