npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

hc-proxy

v2.0.19

Published

honeycomb api proxy express middleware.

Downloads

28

Readme

hc-proxy

api代理模块,node server端代理请求后端service用。

以honeycomb项目为例进行配置

  1. 确定honeycomb项目的启动端口和prefix,比如: 项目的启动端口为8001,prefix为 'example'
  2. 整理远程调用的服务,给每个服务起个英文名称,比如: 上面的两个服务 视频服务(video) 音乐服务(music) 聊天服务(chat)
  3. 配置在router.js中,进行如下配置
  4. 请注意,为了确保安全,所有api只支持白名单
// router.js
const app = require('./app');
const Proxy = require('hc-proxy');
const proxyInstance = new Proxy({
  service: {
    video: {
      endpoint: 'http://localhost:7001/',
      client: 'http',
      api: [
        '/api/aaa',
        '/api/c/d'
      ]
    },
    music: {
      endpoint: 'http://192.168.1.1:7001/',
      client: 'http',
      api: [
        '/api/bbb'
      ]
    },
    dtboostTest: {
      endponit: 'http://localhost:8007/',
      client: 'serviceClient',
      api: [
        '/test',
      ],
      serviceOpt: { // client 代理时会合并以下配置
        pipe: false,
      },
    }
  },
  headers: [
    'x-csrf-token',
    'X-Operator'
  ]
});

// 代理的接口前缀  /api/proxy, 可以自定义
proxyInstance.setProxyPrefix('/api/proxy');

module.exports = function (router) {
  proxyInstance.mount(router, app);
};

配置完成后访问地址

访问地址为:

${服务地址:服务端口/prefix} + ${proxyPrefix} + ${被代理服务名} + ${具体api}

上面的配置案例里:

1. 视频服务:   curl http://localhost:8001/example/api/proxy/video/api/aaa => http://localhost:7001/api/aaa
2. 视频服务:   curl http://localhost:8001/example/api/proxy/video/api/c/somewhat?xxx=123 => http://localhost:7001/api/c/somewhat?xxx=123
3. 音乐服务:   curl http://localhost:8001/example/api/proxy/music/api/bbb => http://192.168.1.1:7001/api/bbb

代理websocket服务

// router.js
const app = require('./app');
const Proxy = require('hc-proxy');
const proxyInstance = new Proxy({
  service: {
    music: {
      endpoint: 'http://192.168.1.1:7001/',
      client: 'http',
      api: [
        '/api/bbb'
      ]
    },
    chat: {
      endpoint: 'http://localhost:7001/',
      client: 'websocket',
      api: [
        '/ws/a'
      ]
    }
  },
  headers: [
    'x-csrf-token',
    'X-Operator'
  ]
});

proxyInstance.setProxyPrefix('/api/proxy');

module.exports = function (router) {
  proxyInstance.mount(router, app);
};

websocket配置完成后访问地址

访问地址为 ${honeycomb服务地址:honeycomb服务端口/honeycomb的prefix} + ${proxyPrefix} + ${被代理服务名} + ${具体api}

1. 音乐服务:   curl http://localhost:8001/example/api/proxy/music/api/bbb => http://192.168.1.1:7001/api/bbb
2. 聊天服务:   curl http://localhost:8001/example/api/proxy/chat/ws/somewhat => http://localhost:7001/ws/somewhat      // 支持websocket

代理文件上传

// router.js
const app = require('./app');
const Proxy = require('hc-proxy');
const proxyInstance = new Proxy({
  service: {
    music: {
      endpoint: 'http://192.168.1.1:7001/',
      client: 'http',
      api: [
        {
          path: '/api/404',
          return: 404
        },
        {
          path: '/api/upload',
          file: true
        },
        {
          path: '/api/upload_limited',
          file: {
            maxFileSize: 100        // 100B
          },
          beforeRequest: (req, options, config) => {},
          beforeResponse: (req, res, data) => {}
        }
      ]
    }
  },
  headers: [
    'x-csrf-token',
    'X-Operator'
  ]
});

proxyInstance.setProxyPrefix('/api/proxy');

module.exports = function (router) {
  proxyInstance.mount(router, app);
};

文件上传代理效果

1. 上传文件1:   curl http://localhost:8001/example/api/proxy/music/api/upload => http://192.168.1.1:7001/api/upload
2. 上传文件2:   curl http://localhost:8001/example/api/proxy/music/api/upload_limited => http://192.168.1.1:7001/api/upload_limited

API document

约定:

  • proxy挂在的http服务称为 "代理服务"
  • 被proxy代理的远端服务称为 "远端服务"

new Proxy(options)

options Object

options.service 详情

{
  ${serviceCode}: {
    /* 每个远端服务的服务地址,如: 'http://localhost:7001' */
    endpoint: ${endpoint},
    accessKeyId: ${accessKeyId},
    accessKeySecret: ${accessKeySecret},
    /* 同 hc-service-client 配置,见文档: https://www.npmjs.com/package/hc-service-client */
    headerExtension: ${headerExtension},
    /* 选填,透传的header列表,同 hc-service-client 配置,见文档: https://www.npmjs.com/package/hc-service-client */
    headers: {Array},
    /* 可选,发起请求的agent,目前只支持'appClient' / 'http' / 'websocket' / 'serviceWebsocket',默认为'appClient',其中 appClient 和 serviceWebsocket 带了honeycomb体系中的签名逻辑 */
    client: ${client},
    /* 接口超时时间,单位毫秒 */
    timeout: ${timeout},
    /* 可选,delete方法使用querystring代理, 默认为true */
    useQuerystringInDelete: ${useQuerystringInDelete}, // 只有 appClient / urllib 模式有效
    /* 可选,用户覆盖的urllibOption,覆盖系统默认值,优先级: service.api.urllibOption > service.urllibOption > hc-proxy默认设置 */
    urllibOption: {Object},                     // 只有 appClient / urllib 模式有效
    /* 覆盖转发时的5XX的errorCode */
    defaultErrorCode: {Number}
    /* 排除列表, 不代理的接口 */
    exclude: {Array}
    /* 路由前缀 */
    routePrefix: {String} 
    /* 是否开启路径支持正则匹配, 默认关闭,开启请确保安全 */
    enablePathWithMatch: {Boolean} false
    api: [
      /* 接口配置可以是简单的一个string */
      '${ApiPathString}',
      {
        /* api访问的path */
        path: {String}
        /* 如若定义,会覆盖proxyPrefix, 给特殊场景定义接口路径用 */
        route: {String}
        /* 接口方法 */
        method: 'GET|POST|PUT|DELETE|PATCH'
        /* 接口超时时间, 单位毫秒,覆盖上面配置的服务的通用超时,通常用来设置特殊接口的超时时长 */
        timeout: {Number},
        /* 是否透传, 开启透传之后,body不落地,直接pipe到远端; 开启pipe之后,body内容不参与签名(签名里的body='') */
        pipe: true,
        /* 请求的默认querystring信息, 用于配置默认的query参数(代理请求时自动加上) */
        defaultQuery: {Object|String},
        /**
         * 发起请求前的hook, beforeRequest(req, apiReq, config) 
         *    @param req {Request} 客户端请求对象request,
         *    @param options {Object} urlib的配置信息,
         *    @param config {Object} api的配置信息
         */
        beforeRequest: {Function(req, options, config)},
        /**
         * 请求从服务接口返回之后的hook,afterResponse(req, res, apiRes) 
         *  @param req {Request} 客户端请求的request对象,
         *  @param res {Response} proxy端请求的response对象,
         *  @param data {Response} 返回数据
         *  @return data
         */
        beforeResponse: {Function(req, res, data)}, 
        /* delete方法使用querystring代理, 默认为true */
        useQuerystringInDelete: {Boolean},
        /** 用户覆盖的urllibOption,覆盖系统默认值,优先级: service.api.urllibOption > service.urllibOption > hc-proxy默认设置 */
        urllibOption: {Object}
      }
    ]
  }
}

通用配置:

  • headers: 选填,同 hc-service-client 配置,见文档: https://www.npmjs.com/package/hc-service-client
  • accessKeyId: 选填,同 hc-service-client 配置,默认 'hc-proxy',详见 https://www.npmjs.com/package/hc-service-client
  • accessKeySecret: 同 hc-service-client 配置,必填,不填时取 app.config.systemToken,详见 https://www.npmjs.com/package/hc-service-client
  • headerExtension: 同 hc-service-client 配置,见文档: https://www.npmjs.com/package/hc-service-client

options.headers Array

options.headers 用于声明proxy需要转发的header。 默认情况下,proxy不转发客户端过来的header,只有在proxyHeaders中配置的header才会被转发。

proxy.setProxyPrefix(proxyPrefix)

  • proxyPrefix

setProxyPrefix方法用于指定 hc-proxy 挂载在代理服务上的总前缀

如: 默认 proxyPrefix = /api/proxy 则: 所有请求远端服务的请求,格式为 ${localHttpServer}/api/proxy/${serviceCode}/${remoteApi}

proxy.mount(router, app)

将proxy的配置挂在到代理服务。

  • router: Express Router instance
  • app: app.server 是一个 http.Server 的实例,honeycomb中,直接 require('./app') 能获得

更多例子

'use strict';

const app = require('./app');
const Proxy = require('hc-proxy');
const proxyInstance = new Proxy({
  service: {
    otm: {
      endpoint: 'http://dev.dtboost.biz.aliyun.test/otm_v2',                           // 自动截取最后的'/'
      client: 'appClient',                                                                // 默认appClient
      timeout: 10000,                                                                     // 默认60000
      api: [
        '/api/a',                                                                         // 支持 * 代理某个path下的所有api
        '/otm_v2/api/entities/list',                                                      // 代理这个 url 的 GET POST PUT DELETE 方法
        {path: '/otm_v2/api/entities/list', method: 'GET'},                                // 只代理 GET 方法
        {path: '/otm_v2/api/entities/list', client: 'appClient'},                          // 显式指定 method
        {path: '/otm_v2/api/schemas', method: ['GET', 'POST']},                            // 只支持 GET POST 方法
        {host: 'http://taobao.com/api', path: '/tag_factory_v2/api/:id', method: 'GET'},   // 不同域时,指定host
        {path: 'http://taobao.com/api', route: '/api/proxy/taobao_api'},                   // 指定route的代理,不指定route时,所有代理接口请求 /<-app_name->/api/proxy 获得代理
        '/otm_v2/api/tags/query_tags_entity_pagenum',                                     // 
        {path: '/otm_v2/api/schemas/:id', route: '/api/proxy/schemas/:id'}                 // 带参数的url,保证route和url中的param一致,也可以不填route
      ]
    },
    websocket: {
      endpoint: 'http://dev.dtboost.biz.aliyun.test/websocket',               // 远程的websocket地址
      client: 'websocket',                                                       // 选择websocket作为连接的client
      api: [
        '/ws'                                                                    // 配置连接路径,不在的路径返回404
      ]
    }
  },
  headers: [
    'x-csrf-token',
    'X-Operator'
  ]
});

proxyInstance.setProxyPrefix('/api/proxy');

module.exports = function (router) {
  proxyInstance.mount(router, app);
};

DEBUG [代理没生效?]

在命令行启动命令前加入DEBUG=hc-proxy

// 以启动命令为 honeycomb start 为例
DEBUG=hc-proxy honeycomb start

// ...
// hc-proxy [GET] /api/proxy/urllib_proxy/urllib -> http://localhost:58062/urllib +0ms
// hc-proxy [POST] /api/proxy/urllib_proxy/urllib -> http://localhost:58062/urllib +3ms
// hc-proxy [DELETE] /api/proxy/urllib_proxy/urllib -> http://localhost:58062/urllib +1ms
// hc-proxy [PUT] /api/proxy/urllib_proxy/urllib -> http://localhost:58062/urllib +0ms
// ...

作用

  • 本地开发时,可以使用这个代理访问远程其它服务(如otm)的问题;
  • 非本地开发环境时,可以不使用代理,而直接访问类似'/otm_v2/api/xxx',以减小内部调用开销,由前端自行控制;