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

Shell脚本本地可见响应但curl客户端收到空回复求助

curl请求Shell简易HTTP服务器返回空响应的排查与解决

我编写了一个Shell脚本实现简易HTTP服务器,调用天气API返回目标城市的湿度和温度。运行脚本后,本地控制台能输出预期响应内容,但执行curl localhost:8080/xyz时收到错误:

curl: (52) Empty reply from server

脚本代码如下:

#!/bin/sh
PORT="${PORT:-8080}"
AUTOR=""
echo "% $(date) -- $AUTOR -- $PORT %"
KEY=
while true; do
  nc -l -p "$PORT" | (
    read -r request_line || exit 1
    CITY_VAL=$(echo "$request_line" | awk '{print substr($2, 2)}')
    while read -r header && [ "$header" != "" ] && [ "$header" != "$(printf '\r')" ]; do
      :
    done
    URL="http://api.weatherapi.com/v1/current.json?key=$KEY&q=$CITY_VAL&aqi=no"
    response=$(wget -q -O - "$URL")
    temp=$(echo "$response" | grep -o '"temp_c":[^,]*' | sed 's/"temp_c"://')
    humidity=$(echo "$response" | grep -o '"humidity":[^,]*' | sed 's/"humidity"://')
    {
      printf "HTTP/1.1 200 OK\r\n"
      printf "Content-Type: text/plain\r\n"
      printf "Content-Length: %s\r\n" "$(expr 16 + ${#humidity} + ${#temp})"
      printf "Connection: close\r\n"
      printf "\r\n"
      printf "Wilgotność %s temperatura %s\r\n" "$humidity" "$temp"
    }
  )
done

本地控制台输出(正常):

./test2.sh
% pon, 28 kwi 2025, 21:48:29 CEST --  -- 8080 %
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 22
Connection: close

Wilgotność 44 temperatura 12.4

核心原因

脚本的管道方向错误,导致响应未发送给客户端:

  • nc -l -p "$PORT" | (...) 是将nc接收到的客户端请求(nc的stdout)传递给子shell处理;
  • 子shell生成的响应直接输出到终端stdout,而非回传给nc的连接通道(nc的stdin),因此客户端无法收到任何数据,返回空响应。

解决办法

根据nc版本的不同,有两种可靠的修正方式:

方式1:利用命名管道实现双向通信(兼容所有POSIX环境)

通过命名管道将子shell的响应回传给nc,让nc发送给客户端:

#!/bin/sh
PORT="${PORT:-8080}"
AUTOR=""
echo "% $(date) -- $AUTOR -- $PORT %"
KEY=

# 创建临时命名管道,脚本退出时自动清理
mkfifo request_pipe response_pipe
trap 'rm -f request_pipe response_pipe' EXIT

while true; do
  # nc读取response_pipe的响应发给客户端,将客户端请求写入request_pipe
  cat response_pipe | nc -l -p "$PORT" > request_pipe &
  NC_PID=$!

  # 处理请求并生成响应
  (
    read -r request_line < request_pipe || exit 1
    CITY_VAL=$(echo "$request_line" | awk '{print substr($2, 2)}')
    while read -r header && [ "$header" != "" ] && [ "$header" != "$(printf '\r')" ]; do
      :
    done
    URL="http://api.weatherapi.com/v1/current.json?key=$KEY&q=$CITY_VAL&aqi=no"
    response=$(wget -q -O - "$URL")
    temp=$(echo "$response" | grep -o '"temp_c":[^,]*' | sed 's/"temp_c"://')
    humidity=$(echo "$response" | grep -o '"humidity":[^,]*' | sed 's/"humidity"://')
    
    # 将响应写入response_pipe,由nc发送给客户端
    {
      printf "HTTP/1.1 200 OK\r\n"
      printf "Content-Type: text/plain\r\n"
      printf "Content-Length: %s\r\n" "$(expr 16 + ${#humidity} + ${#temp})"
      printf "Connection: close\r\n"
      printf "\r\n"
      printf "Wilgotność %s temperatura %s\r\n" "$humidity" "$temp"
    } > response_pipe
  )

  wait $NC_PID
done

方式2:使用nc的-e选项(仅GNU netcat支持)

如果你的系统安装的是GNU netcat(而非OpenBSD版本),可以直接用-e选项将连接的stdin/stdout绑定到处理逻辑,简化代码:

#!/bin/sh
PORT="${PORT:-8080}"
AUTOR=""
echo "% $(date) -- $AUTOR -- $PORT %"
KEY=

# 定义处理请求的函数
handle_request() {
  read -r request_line || exit 1
  CITY_VAL=$(echo "$request_line" | awk '{print substr($2, 2)}')
  while read -r header && [ "$header" != "" ] && [ "$header" != "$(printf '\r')" ]; do
    :
  done
  URL="http://api.weatherapi.com/v1/current.json?key=$KEY&q=$CITY_VAL&aqi=no"
  response=$(wget -q -O - "$URL")
  temp=$(echo "$response" | grep -o '"temp_c":[^,]*' | sed 's/"temp_c"://')
  humidity=$(echo "$response" | grep -o '"humidity":[^,]*' | sed 's/"humidity"://')
  
  # 直接输出响应,由nc发送给客户端
  {
    printf "HTTP/1.1 200 OK\r\n"
    printf "Content-Type: text/plain\r\n"
    printf "Content-Length: %s\r\n" "$(expr 16 + ${#humidity} + ${#temp})"
    printf "Connection: close\r\n"
    printf "\r\n"
    printf "Wilgotność %s temperatura %s\r\n" "$humidity" "$temp"
  }
}

while true; do
  # -e选项指定处理请求的命令,自动绑定连接的IO
  nc -l -p "$PORT" -e sh -c 'handle_request'
done

内容的提问来源于stack exchange,提问作者Hubert Kiszka

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 06:52:33