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

为何仅Firefox能显示自制HTTP服务器响应?Chrome/Chromium无内容

Chrome/Chromium无法显示HTTP服务器响应,Firefox却正常的原因

测试背景

为理清HTTP与TCP的关系,我编写了一个监听特定地址+端口的TCP套接字服务器,通过浏览器访问测试后发现:

  • 服务器accept()的套接字收到的是符合HTTP规范的文本内容
  • 推测要让浏览器显示内容,服务器需向套接字写入符合HTTP规范的响应
  • 基于最小化HTTP响应示例编写服务器代码后,出现兼容性问题:Firefox能正常显示"Hello World!",但Chrome和Chromium页面空白

浏览器请求内容

Chrome发送的请求

GET / HTTP/1.1
Host: 127.0.0.23:9018
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9

Firefox发送的请求

GET / HTTP/1.1
Host: 127.0.0.23:9018
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1

服务器代码

#include <arpa/inet.h>                                                                         
#include <cerrno>                                                                               
#include <cstdio>                                                                               
#include <cstring>                                                                              
#include <fcntl.h>                                                                              
#include <iostream>                                                                             
#include <netinet/in.h>                                                                         
#include <pthread.h>                                                                            
#include <semaphore.h>                                                                          
#include <stdexcept>                                                                            
#include <sstream>                                                                              
#include <sys/types.h>                                                                          
#include <sys/socket.h>                                                                         
#include <unistd.h>                                                                             
                                                                                                
#define IP "127.0.0.23"                                                                         
#define PORT (9018)                                                                             
                                                                                                
/**                                                                                             
 * A primitive, POC-level HTTP server that accepts its first incoming connection               
 * and sends back a minimal HTTP OK response.                                                   
 */                                                                                             
class Server {                                                                                  
private:                                                                                        
  static const std::string ip_;                                                                 
  static const std::uint16_t port_{PORT};                                                       
  int listen_sock_;                                                                             
  pthread_t tid_;                                                                               
                                                                                                
public:                                                                                         
  /**                                                                                           
   * Ctor: create and bind listen_sock_ and start a thread for startRoutine().                 
   */                                                                                           
  Server() {                                                                                    
    using namespace std;                                                                        
    int result;                                                                                 
                                                                                                
    if (! createSocket()) { throw runtime_error("failed creating socket"); }                    
    if (! bindSocket()) { throw runtime_error("failed binding socket"); }                       
                                                                                                
    if ((result = pthread_create(&tid_, NULL, startRoutine, this))) {                           
      std::stringstream ss;                                                                     
                                                                                                
      ss << "pthread_create() error " << errno << "(" << result << ")";                         
      std::cerr << ss.str() << std::endl;                                                       
      throw runtime_error("failed spawning Server thread");                                     
    }                                                                                           
  }                                                                                             
                                                                                                
  /** Dtor: wait for the spawned thread and destroy listen_sock_. */                            
  ~Server() {                                                                                   
    pthread_join( tid_, NULL );                                                                 
    destroySocket();                                                                             
  }                                                                                             
                                                                                                
private:                                                                                        
  /** Creates listen_sock_ as a stream socket. */                                               
  bool createSocket() {                                                                         
    listen_sock_ = socket(PF_INET, SOCK_STREAM, 0);                                             
                                                                                                
    if (listen_sock_ < 0) {                                                                     
      std::stringstream ss;                                                                     
                                                                                                
      ss << "socket() error " << errno << "(" << strerror(errno) << ")";                        
      std::cerr << ss.str() << std::endl;                                                       
    }                                                                                           
                                                                                                
    return (listen_sock_ >= 0);                                                                 
  }                                                                                             

  /** Shuts down and closes listen_sock_. */                                                    
  void destroySocket() {                                                                        
    if (listen_sock_ >= 0) {                                                                    
      shutdown(listen_sock_, SHUT_RDWR);                                                        
      close(listen_sock_);                                                                     
    }                                                                                           
  }                                                                                             

  /** Binds listen_sock_ to ip_ and port_. */                                                   
  bool bindSocket() {                                                                           
    int ret;                                                                                    
    sockaddr_in me;                                                                             
    me.sin_family = PF_INET;                                                                    
    me.sin_port = htons(port_);                                                                 
    me.sin_addr.s_addr = inet_addr(ip_.c_str());
    int optval = 1;                                                                             

    setsockopt(listen_sock_, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval);

    if ((ret = bind(listen_sock_, (sockaddr*)&me, sizeof me))) {
      std::stringstream ss;                                                                     

      ss << "bind() error " << errno << "(" << strerror(errno) << ")";
      std::cerr << ss.str() << std::endl;                                                       
    }                                                                                           

    return (! ret);                                                                             
  }                                                                                             

  /**                                                                                           
   * Accept a connection from listen_sock_.                                                     
   * Caller guarantees listen_sock_ has been listen()ed to already.
   * @param tv [in, out] How long to wait to accept a connection.
   * @return accepted socket; -1 on any error.                                                  
   */                                                                                           
  int acceptConnection(timeval& tv) {                                                           
    int sock = -1;                                                                              
    int ret;                                                                                    
    fd_set readfds;                                                                             
    sockaddr_in peer;                                                                           
    socklen_t addrlen = sizeof peer;                                                            

    FD_ZERO(&readfds);                                                                         
    FD_SET(listen_sock_, &readfds);                                                             
    ret = select(listen_sock_ + 1, &readfds, NULL, NULL, &tv);

    if (ret < 0) {                                                                              
      std::stringstream ss;                                                                     

      ss << "select() error " << errno << "(" << strerror(errno) << ")";
      std::cerr << ss.str() << std::endl;                                                       

      return sock;                                                                              
    }                                                                                           
    else if (! ret) {                                                                           
      std::cout << "no connections within " << tv.tv_sec << "seconds"
        << std::endl;                                                                           

      return sock;                                                                              
    }                                                                                           

    if ((sock = accept(listen_sock_, (sockaddr*)&peer, &addrlen)) < 0) {
      std::stringstream ss;                                                                     

      ss << "accept() error " << errno << "(" << strerror(errno) << ")";
      std::cerr << ss.str() << std::endl;                                                       
    }                                                                                           
    else {                                                                                      
      std::stringstream ss;                                                                     

      ss << "socket " << sock << " accepted connection from "
        << inet_ntoa( peer.sin_addr ) << ":" << ntohs(peer.sin_port);
      std::cout << ss.str() << std::endl;                                                       
    }                                                                                           

    return sock;                                                                               
  }

  /** Read from the specified socket and dump to stdout. */
  static void dumpReceivedContent(const int& sock) {
    fd_set readfds;                                                                             
    struct timeval tv = {30, 0};                                                                
    int ret;                                                                                    

    FD_ZERO(&readfds);                                                                         
    FD_SET(sock, &readfds);                                                                     
    ret = select(sock + 1, &readfds, NULL, NULL, &tv);

    if (ret < 0) {                                                                              
      std::stringstream ss;                                                                     

      ss << "select() error " << errno << "(" << strerror(errno) << ")";
      std::cerr << ss.str() << std::endl;                                                       

      return;                                                                                   
    }                                                                                           
    else if (! ret) {                                                                           
      std::cout << "no content received within " << tv.tv_sec << "seconds"
        << std::endl;                                                                           

      return;                                                                                   
    }                                                                                           

    if (FD_ISSET(sock, &readfds)) {                                                             
      ssize_t bytes_read;                                                                       
      char buf[80] = {0};                                                                       

      fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK);
      std::cout << "received content:" << std::endl;
      std::cout << "----" << std::endl;                                                         
      while ((bytes_read = read(sock, buf, (sizeof buf) - 1)) >= 0) {
        buf[bytes_read] = '\0';                                                                 
        std::cout << buf;                                                                       
      }                                                                                         
      std::cout << std::endl << "----" << std::endl;
    }                                                                                           
  }                                                                                             

  /** Write a minimal HTTP OK response to the specified socker. */
  static void sendMinHttpResponse(const int& sock) {
    static const std::string resp =                                                             
      "HTTP/1.1 200 OK\r\n"                                                                     
      "Content-Length: 13\r\n"                                                                 
      "Content-Type: text/plain\r\n\r\nHello World!";
    write(sock, resp.c_str(), resp.length());                                                   
  }                                                                                             

  /**                                                                                           
   * Thread start routine: listen for, then accept connections; dump received
   * content; send a minimal response.                                                          
   */                                                                                           
  static void* startRoutine(void* arg) {                                                        
    Server* s;                                                                                  

    if (! (s = (Server*)arg)) {                                                                 
      std::cout << "Bad arg" << std::endl;                                                      
      return NULL;                                                                              
    }                                                                                           

    if (listen(s->listen_sock_, 3)) {                                                           
      std::stringstream ss;                                                                     

      ss << "listen() error " << errno << "(" << strerror(errno) << ")";
      std::cerr << ss.str() << std::endl;                                                       

      return NULL;                                                                              
    }                                                                                           

    std::cout << "Server accepting connections at "
      << s->ip_ << ":" << s->port_ << std::endl;

    {                                                                                           
      timeval tv = { 30, 0 };                                                                   

      int sock = s->acceptConnection(tv);                                                       

      if (sock < 0) {                                                                           
        std::cout << "no connections accepted" << std::endl;

        return NULL;                                                                           
      }                                                                                         

      dumpReceivedContent(sock);                                                                
      sendMinHttpResponse(sock);                                                                
      shutdown(sock, SHUT_RDWR);                                                                
      close(sock);                                                                              
    }                                                                                           

    return NULL;                                                                               
  }                                                                                             
};                                                                                              

const std::string Server::ip_{IP};                                                              

int main( int argc, char* argv[] ) {                                                            
  Server s;                                                                                     
  return 0;                                                                                     
}

核心问题

将Chrome和Chromium指向服务器地址127.0.0.23:9018时,页面为空白无内容;但Firefox能正常显示预期的"Hello World!"字符串。为何会出现这种浏览器兼容性差异?


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 07:57:15