第一站 - 轻松上网从此开始!

上网第一站

当前位置: > SEO >

如何编写一个 HTTP 反向代理服务器(3)

时间:2017-12-13 09:07来源:我来投稿获取授权
以下内容来自网络或网友投稿,www.swdyz.com不承担连带责任,如有侵权问题请联系我删除。投稿如果是首发请注明‘第一站首发’。如果你对本站有什么好的要求或建议。那么都非常感谢你能-联系我|版权认领
上文我们已经完成了一个基本的 HTTP 反向代理程序,也通过简单的方法验证了它是能正常工作的。但是,我们并没有足够的测试,比如只验证了 GET 请求,

  上文我们已经完成了一个基本的 HTTP 反向代理程序,也通过简单的方法验证了它是能正常工作的。但是,我们并没有足够的测试,比如只验证了 GET 请求,并没有验证 POST 请求或者其他的请求方法。而且通过手工去做更多的测试也比较麻烦,很容易遗漏。所以,接下来我们要给它加上自动化的单元测试。

  在本文中我们选用在 Node.js 界应用广泛的 mocha 作为单元测试框架,搭配使用 supertest 来进行 HTTP 接口请求的测试。由于 supertest 已经自带了一些基本的断言方法,我们暂时不需要chai 或者 should 这样的第三方断言库。

  首先执行 npm init 初始化一个 package.json 文件,并执行以下命令安装 mocha 和 supertest :

  npm install mocha supertest --save-dev

  然后新建文件 test.js :

  const http = require("http");

  const log = require("./log");

  const reverseProxy = require("./proxy");

  const { expect } = require("chai");

  const request = require("supertest");

  // 创建反向代理服务器

  function startProxyServer() {

  return new Promise((resolve, reject) => {

  const server = http.createServer(

  reverseProxy({

  servers: ["127.0.0.1:3001", "127.0.0.1:3002", "127.0.0.1:3003"]

  })

  );

  log("反向代理服务器已启动");

  resolve(server);

  });

  }

  // 创建演示服务器

  function startExampleServer(port) {

  return new Promise((resolve, reject) => {

  const server = http.createServer(function(req, res) {

  const chunks = [];

  req.on("data", chunk => chunks.push(chunk));

  req.on("end", () => {

  const buf = Buffer.concat(chunks);

  res.end(`${port}: ${req.method} ${req.url} ${buf.toString()}`.trim());

  });

  });

  server.listen(port, () => {

  log("服务器已启动: %s", port);

  resolve(server);

  });

  server.on("error", reject);

  });

  }

  describe("测试反向代理", function() {

  let server;

  let exampleServers = [];

  // 测试开始前先启动服务器

  before(async function() {

  exampleServers.push(await startExampleServer(3001));

  exampleServers.push(await startExampleServer(3002));

  exampleServers.push(await startExampleServer(3003));

  server = await startProxyServer();

  });

  // 测试结束后关闭服务器

  after(async function() {

  for (const server of exampleServers) {

  server.close();

  }

  });

  it("顺序循环返回目标地址", async function() {

  await request(server)

  .get("/hello")

  .expect(200)

  .expect(`3001: GET /hello`);

  await request(server)

  .get("/hello")

  .expect(200)

  .expect(`3002: GET /hello`);

  await request(server)

  .get("/hello")

  .expect(200)

  .expect(`3003: GET /hello`);

  await request(server)

  .get("/hello")

  .expect(200)

  .expect(`3001: GET /hello`);

  });

  it("支持 POST 请求", async function() {

  await request(server)

  .post("/xyz")

  .send({

  a: 123,

  b: 456

  })

  .expect(200)

  .expect(`3002: POST /xyz {"a":123,"b":456}`);

  });

  });

  说明:

  在单元测试开始前,需要通过 before() 来注册回调函数,以便在开始执行测试用例时先把服务器启动起来

  同理,通过 after() 注册回调函数,以便在执行完所有测试用例后把服务器关闭以释放资源(否则 mocha 进程不会退出)

  使用 supertest 发送请求时,代理服务器不需要监听端口,只需要将 server 实例作为调用参数即可

  接着修改 package.json 文件的 scripts 部分:

  {

  "scripts": {

  "test": "mocha test.js"

  }

  }

  执行以下命令开始测试:

  npm test

  如果一切正常,我们应该会看到这样的输出结果,其中 passing 这样的提示表示我们的测试完全通过了:

  测试反向代理

  2017-12-12 18:28:15 服务器已启动: 3001

  2017-12-12 18:28:15 服务器已启动: 3002

  2017-12-12 18:28:15 服务器已启动: 3003

  2017-12-12 18:28:15 反向代理服务器已启动

  2017-12-12 18:28:15 [GET /hello => 127.0.0.1:3001] 代理请求

  2017-12-12 18:28:15 [GET /hello => 127.0.0.1:3001] 响应: 200

  2017-12-12 18:28:15 [GET /hello => 127.0.0.1:3002] 代理请求

  2017-12-12 18:28:15 [GET /hello => 127.0.0.1:3002] 响应: 200

  2017-12-12 18:28:15 [GET /hello => 127.0.0.1:3003] 代理请求

  2017-12-12 18:28:15 [GET /hello => 127.0.0.1:3003] 响应: 200

  2017-12-12 18:28:15 [GET /hello => 127.0.0.1:3001] 代理请求

  2017-12-12 18:28:15 [GET /hello => 127.0.0.1:3001] 响应: 200

  ✓ 顺序循环返回目标地址

  2017-12-12 18:28:15 [POST /xyz => 127.0.0.1:3002] 代理请求

  2017-12-12 18:28:15 [POST /xyz => 127.0.0.1:3002] 响应: 200

  ✓ 支持 POST 请求

  2 passing (45ms)

  当然以上的测试代码还远远不够,剩下的就交给读者们来实现了。

  接口改进

  如果要设计成一个比较通用的反向代理中间件,我们还可以通过提供一个生成 http.ClientRequest 的函数来实现在代理时动态修改请求:

  reverseProxy({

  servers: ["127.0.0.1:3001", "127.0.0.1:3002", "127.0.0.1:3003"],

  request: function(req, info) {

  // info 是默认生成的 request options 对象

  // 我们可以动态增加请求头,比如当前请求时间戳

  info.headers["X-Request-Timestamp"] = Date.now();

  // 返回 http.ClientRequest 对象

  return http.request(info);

  }

  });

  然后在原来的 http.request(info, (res2) => {}) 部分可以改为监听 response 事件:

  const req2 = http.request(options.request(info));

  req2.on("response", res2 => {});

  同理,我们也可以通过提供一个函数来修改部分的响应内容:

  reverseProxy({

  servers: ["127.0.0.1:3001", "127.0.0.1:3002", "127.0.0.1:3003"],

  response: function(res, info) {

  // info 是发送代理请求时所用的 request options 对象

  // 我们可以动态设置一些响应头,比如实际代理的模板服务器地址

  res.setHeader("X-Backend-Server", `${info.hostname}:${info.port}`);

  }

  });

  此处只发散一下思路,具体实现方法和代码就不再赘述了。

  总结

(责任编辑:admin)
织梦二维码生成器
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
发布者资料
第一站编辑 查看详细资料 发送留言 加为好友 用户等级:注册会员 注册时间:2012-05-22 19:05 最后登录:2014-08-08 03:08
栏目列表
推荐内容
分享按鈕