Skip to content
js
let fs = require("fs");
const http = require("node:http");
const net = require("node:net");
const { URL } = require("node:url");

//把route函数当作参数传给server,就可以处理server接受到的request的url参数。
// 从而根据路由做出响应
function route(url) {
  console.log("你请求的地址是:" + url);
}

/**
 * @listening
 * @maxHeadersCount
 * @requestTimeout
 * @itemout
 * @keepAliveTimeout number
 */
const proxy = http.createServer((req, response) => {
  route(req.url);
  let url =
    req.url == "/" ? "../../../public/index.html" : "../pages" + req.url;
  if (fs.existsSync(url)) {
    let data = fs.readFileSync(url);
    response.write(data);
  } else {
    let data = fs.readFileSync("../pages/404.html");
    response.write(data);
  }

  /** response
   * @flushHeaders() 刷新响应头
   * @getHeader(name)
   * @hasHeader(name)
   * @setHeader(key,name)
   * @removeHeader(name)
   * @setTimeout(msecs[, callback])
   * @write(chunk[, encoding][, callback]) 发送一块响应正文。可以多次调用此方法以提供正文的连续部分。
   * @req 对原始的 HTTP request 对象的引用。
   * @sendDate
   * @socket
   * @statusCode
   * @statusMessage
   * @strictContentLength
   *
   */
  response.setHeader("Content-Type", "text/html");
  response.setHeader("Content-Length", Buffer.byteLength(body));
  response.setHeader("Set-Cookie", ["type=ninja", "language=javascript"]);
  const contentType = response.getHeader("content-type");
  // contentType is 'text/html'
  const contentLength = response.getHeader("Content-Length");
  // contentLength is of type number
  const setCookie = response.getHeader("set-cookie");
  // setCookie is of type string[]
  response.writeHead(200, { "Content-Type": "text/plain" });
  response.end("okay", "utf-8", () => {
    console.log("标明已发送所有的响应头和正文。必须在每个响应上调用");
  });
});

proxy.on("request", (res, response) => {
  console.log("每次有请求时触发。每个连接可能有多个请求");
});

//当建立新的 TCP 流时会触发此事件。socket 通常是 net.Socket 类型的对象
proxy.on("connect", (req, clientSocket, head) => {
  // Connect to an origin server
  const { port, hostname } = new URL(`http://${req.url}`);
  const serverSocket = net.connect(port || 80, hostname, () => {
    clientSocket.write(
      "HTTP/1.1 200 Connection Established\r\n" +
        "Proxy-agent: Node.js-Proxy\r\n" +
        "\r\n"
    );
    serverSocket.write(head);
    serverSocket.pipe(clientSocket);
    clientSocket.pipe(serverSocket);
  });
});

// Now that proxy is running
proxy.listen(1337, "127.0.0.1", error => {
  if (error) {
    console.log(error, "error");
    throw error;
  }
  console.log("服务器已经在8080端口启动成功!");

  /** req
   * @protocol
   * @host
   * @method
   * @path
   * @maxHeadersCount
   * @reusedSocket
   * @socket
   */
  const req = http.request({
    port: 1337,
    host: "127.0.0.1",
    method: "CONNECT",
    path: "www.google.com:80",
  });

  req.setHeader("content-type", "text/html");
  req.setHeader("Content-Length", Buffer.byteLength(body));
  req.setHeader("Cookie", ["type=ninja", "language=javascript"]);
  const contentType = req.getHeader("Content-Type");
  // 'contentType' is 'text/html'
  const contentLength = req.getHeader("Content-Length");
  // 'contentLength' is of type number
  const cookie = req.getHeader("Cookie");
  // 'cookie' is of type string[]
  req.removeHeader("Cookie");

  const hasContentType = req.hasHeader("content-type");

  req.end();

  req.on("connect", (res, socket, head) => {
    console.log("got connected!");

    // Make a request over an HTTP tunnel
    socket.write(
      "GET / HTTP/1.1\r\n" +
        "Host: www.google.com:80\r\n" +
        "Connection: close\r\n" +
        "\r\n"
    );
    socket.on("data", chunk => {
      console.log(chunk.toString());
    });
    socket.on("end", () => {
      proxy.close();
    });
  });
});

// 关闭连接
server.close(() => {
  console.log("server on port 8000 closed successfully");
});

根据 MIT 许可证发布