我正在使用Cloud9作为一个环境。io ubuntu虚拟机在线IDE和我已经减少了这个错误,只是运行应用程序与Webpack开发服务器。

我用:

webpack-dev-server -d --watch --history-api-fallback --host $IP --port $PORT

$IP是一个包含主机地址的变量 $PORT包含端口号。

当在Cloud 9中部署应用程序时,我被指示使用这些变量,因为它们有默认的IP和PORT信息。

服务器启动并编译代码,没有问题,但它没有显示索引文件。只有一个空白屏幕与“无效的主机标题”作为文本。

这是请求:

GET / HTTP/1.1
Host: store-client-nestroia1.c9users.io
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 
(KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
Accept: 
text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
DNT: 1
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: en-US,en;q=0.8

这是我的package.json:

{
  "name": "workspace",
  "version": "0.0.0",
  "scripts": {
    "dev": "webpack -d --watch",
    "server": "webpack-dev-server -d --watch --history-api-fallback --host $IP --port $PORT",
    "build": "webpack --config webpack.config.js"
  },
  "author": "Artur Vieira",
  "license": "ISC",
  "dependencies": {
    "babel-core": "^6.18.2",
    "babel-loader": "^6.2.8",
    "babel-preset-es2015": "^6.18.0",
    "babel-preset-react": "^6.16.0",
    "babel-preset-stage-0": "^6.24.1",
    "file-loader": "^0.11.1",
    "node-fetch": "^1.6.3",
    "react": "^15.5.4",
    "react-bootstrap": "^0.30.9",
    "react-dom": "^15.5.4",
    "react-router": "^4.1.1",
    "react-router-dom": "^4.1.1",
    "url-loader": "^0.5.8",
    "webpack": "^2.4.1",
    "webpack-dev-server": "^2.4.4",
    "whatwg-fetch": "^2.0.3"
  }
}

这是webpack.config.js:

const path = require('path');

module.exports = {

  entry: ['whatwg-fetch', "./app/_app.jsx"], // string | object | array
  // Here the application starts executing
  // and webpack starts bundling
  output: {
    // options related to how webpack emits results

    path: path.resolve(__dirname, "./public"), // string
    // the target directory for all output files
    // must be an absolute path (use the Node.js path module)

    filename: "bundle.js", // string
    // the filename template for entry chunks

    publicPath: "/public/", // string
    // the url to the output directory resolved relative to the HTML page
  },

  module: {
    // configuration regarding modules

    rules: [
      // rules for modules (configure loaders, parser options, etc.)
      {
        test: /\.jsx?$/,
        include: [
          path.resolve(__dirname, "./app")
        ],
        exclude: [
          path.resolve(__dirname, "./node_modules")
        ],
        loader: "babel-loader?presets[]=react,presets[]=es2015,presets[]=stage-0",
        // the loader which should be applied, it'll be resolved relative to the context
        // -loader suffix is no longer optional in webpack2 for clarity reasons
        // see webpack 1 upgrade guide
      },
      {
        test: /\.css$/,
        use: [ 'style-loader', 'css-loader' ]
      },
      {
        test: /\.(png|jpg|jpeg|gif|svg|eot|ttf|woff|woff2)$/,
        loader: 'url-loader',
        options: {
          limit: 10000
        }
      }
    ]
  },

  devServer: {
    compress: true
  }
}

Webpack开发服务器返回这个,因为我的主机设置。在webpack-dev-server/lib/Server.js第60行。从https://github.com/webpack/webpack-dev-server

我的问题是我如何设置正确通过这个检查。任何帮助都将不胜感激。


当前回答

当发出HTTP请求时,默认情况下,浏览器/客户端包括“主机”(来自URL)作为原始HTTP请求头的一部分。作为额外的安全性/完整性检查的一部分(现在很常见),Host头必须与HTTP服务器所期望的内容相匹配,以便服务器向您发送您所期望的内容。

默认情况下,Webpack Dev Server (WDS)只接受带有主机头的传入HTTP请求,该主机头与一些常见主机名(如localhost)匹配。当一个带有意外Host头的请求进入时,服务器仍然需要用一些东西来响应。因此,它尽其所能:发送一个带有标准HTTP错误代码的响应,并在HTML中发送一条人类可读的消息:“Invalid Host header”。

现在,至于如何解决这个问题,基本上有两个选择。告诉WDS接受更多(或全部)“Host”报头或修复与HTTP请求一起发送的Host报头。

配置Webpack

Generally, it's easier (and more correct) to tell the WDS configuration to allow more "Host"names to be used. By default, WDS only accepts connections from the local development machine and so, by default, only needs to support the hostname localhost. Most commonly this "Invalid Host header" issue comes up when trying to server to other clients on the network. After adding host: '0.0.0.0' to the devServer configuration, WDS needs to be told which names might be used by clients to talk to it. require('os').hostname() is usually (one of) the hostnames but other names could be just as valid. Because of this, WDS accepts a list of allowed names.

module.exports = {
  //...
  devServer: {
    allowedHosts: [
      require('os').hostname(),
      'host.com',
      'subdomain.host.com',
      'subdomain2.host.com',
      'host2.com'
    ]
  }
};

然而,有时获得正确的列表是比它的价值更多的麻烦,它足够好,只是告诉WDS忽略Host头检查。在Webpack 4中,它是disableHostCheck选项。在Webpack 5中,allowwedhosts选项可以设置为单个字符串'all'(没有数组)。

创建React App (CRA)

流行的程序包create-react-app内部使用Webpack。CRA有一个额外的环境变量来覆盖这个特定的设置:DANGEROUSLY_DISABLE_HOST_CHECK=true。

发送不同的主机报头

如果改变Webpack的配置是不可能的,另一种解决方法是改变客户端的配置。

一个技巧是在客户机上使用hosts文件,以便所需的主机名映射到服务器的IP。

更常见的情况是反向代理位于WDS的前面。对于发送到后端(WDS)的请求,不同的代理具有不同的默认值。正如VivekDev的回答所建议的那样,您可能需要专门将Host头添加到后端请求中。

其他回答

当使用webpack-dev-server时,将此配置添加到webpack配置文件中(您仍然可以将主机指定为0.0.0.0)。

devServer: {
    disableHostCheck: true,
    host: '0.0.0.0',
    port: 3000
}

我通过在nginx配置中添加主机头的代理来解决这个问题,就像这样:

server {
    listen 80;
    server_name     localhost:3000;

    location / {
        proxy_pass http://myservice:8080/;

        proxy_set_header HOST $host;
        proxy_set_header Referer $http_referer;
    }
}

我补充说:

proxy_set_header主机

$http_referer;

我发现,我需要将devServer的公共属性设置为请求的主机值。因此,它将显示在该外部地址。

所以我需要在我的webpack.config.js中

devServer: {
  compress: true,
  public: 'store-client-nestroia1.c9users.io' // That solved it
}

另一个解决方案是在CLI中使用它:

webpack-dev-server --public $C9_HOSTNAME   <-- var for Cloud9 external IP

我使用nginx运行在docker容器内部,根据url路由流量。

在nginx配置文件中添加以下两行代码,为我修复了“无效主机头”的错误。参见下面的配置文件(default.conf)。

proxy_set_header Host            $http_host;
proxy_set_header X-Forwarded-For $remote_addr;

首先,下面是我简单的两行Dockerfile来创建nginx容器,然后用路由配置它。

FROM nginx
COPY ./default.conf /etc/nginx/conf.d/default.conf

因此,当构建映像时,default.conf文件被复制到nginx容器内的配置目录。

接下来,default.conf文件如下所示。

upstream ui {
    # The ui service below is a ui app running inside of a container. Inside of the container, the ui app is listening on port 3000. 
    server ui:3000;
}

upstream node-app {
    # The node-app service below is a server app running inside of a container. Inside of the container, the server is listening on port 8080. 
    server node-app:8080;
}

server {
    listen 80;

    location / {
        # The root path, with is '/' will routed to ui.
        proxy_pass http://ui;

        ################## HERE IS THE FIX ##################
        # Adding the following two lines of code finally made the error "Invalid Host header" go away.

        # The following two headers will pass the client ip address to the upstream server
        # See upstream ui at the very begining of this file.

        proxy_set_header Host            $http_host;
        proxy_set_header X-Forwarded-For $remote_addr;      
    }


    location /api {
        # Requests that have '/api' in the path are rounted to the express server.
        proxy_pass http://node-app;
    }
}
# 

最后,如果你想看一下我的docker compose文件,它有所有的服务(包括nginx),在这里

version: '3'
services:
  # This is the nginx service. 
  proxy:
    build:
      # The proxy folder will have the Dockerfile and the default.conf file I mentioned above. 
      context: ./proxy 
    ports:
      - 7081:80

  redis-server:
    image: 'redis'

  node-app:
    restart: on-failure
    build: 
      context: ./globoappserver
    ports:
      - "9080:8080"     
    container_name: api-server

  ui:
    build:
      context: ./globo-react-app-ui
    environment:
        - CHOKIDAR_USEPOLLING=true      
    ports:
      - "7000:3000"
    stdin_open: true 
    volumes:
      - ./globo-react-app-ui:/usr/app

  postgres:
    image: postgres
    volumes:
      - postgres:/var/lib/postgresql/data
      - ./init-database.sql:/docker-entrypoint-initdb.d/init-database.sql
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=password

volumes:
  postgres:

2021年使用webpack-dev-server v4+的人,

allowedHosts和disableHostsCheck被移除,取而代之的是allowedHosts: 'all'

要摆脱这个错误,将你的devServer更改为:

devServer: {
  compress: true,
  allowedHosts: 'all'
}