├── .autod.conf.js ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── app.js ├── app └── middleware │ └── http_proxy.js ├── config └── config.default.js ├── index.d.ts ├── package.json ├── test ├── fixtures │ └── apps │ │ └── http-proxy-test │ │ ├── app │ │ ├── controller │ │ │ └── home.js │ │ └── router.js │ │ ├── config │ │ ├── config.default.js │ │ └── plugin.js │ │ └── package.json └── http-proxy.test.js └── yarn.lock /.autod.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | write: true, 5 | prefix: '^', 6 | plugin: 'autod-egg', 7 | test: [ 8 | 'test', 9 | 'benchmark', 10 | ], 11 | devdep: [ 12 | 'egg', 13 | 'egg-ci', 14 | 'egg-bin', 15 | 'egg-path-matching', 16 | 'autod', 17 | 'autod-egg', 18 | 'eslint', 19 | 'eslint-config-egg', 20 | 'http-proxy-middleware', 21 | 'koa2-connect', 22 | 'lodash', 23 | 'webstorm-disable-index' 24 | ], 25 | exclude: [ 26 | './test/fixtures', 27 | './docs', 28 | './coverage', 29 | ], 30 | }; 31 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | coverage 2 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint-config-egg" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | logs/ 2 | npm-debug.log 3 | node_modules/ 4 | coverage/ 5 | .idea/ 6 | run/ 7 | .DS_Store 8 | *.swp 9 | 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - '13' 5 | - '12' 6 | - '10' 7 | before_install: 8 | - npm i npminstall -g 9 | install: 10 | - npminstall 11 | script: 12 | - npm run ci 13 | after_script: 14 | - npminstall codecov && codecov 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Chun-Kai Wang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # egg-http-proxy 2 | 3 | [![NPM version][npm-image]][npm-url] 4 | [![build status][travis-image]][travis-url] 5 | [![Test coverage][codecov-image]][codecov-url] 6 | [![David deps][david-image]][david-url] 7 | [![Known Vulnerabilities][snyk-image]][snyk-url] 8 | [![npm download][download-image]][download-url] 9 | 10 | [npm-image]: https://img.shields.io/npm/v/egg-http-proxy.svg?style=flat-square 11 | [npm-url]: https://npmjs.org/package/egg-http-proxy 12 | [travis-image]: https://img.shields.io/travis/chunkai1312/egg-http-proxy.svg?style=flat-square 13 | [travis-url]: https://travis-ci.org/chunkai1312/egg-http-proxy 14 | [codecov-image]: https://img.shields.io/codecov/c/github/chunkai1312/egg-http-proxy.svg?style=flat-square 15 | [codecov-url]: https://codecov.io/github/chunkai1312/egg-http-proxy?branch=master 16 | [david-image]: https://img.shields.io/david/chunkai1312/egg-http-proxy.svg?style=flat-square 17 | [david-url]: https://david-dm.org/chunkai1312/egg-http-proxy 18 | [snyk-image]: https://snyk.io/test/npm/egg-http-proxy/badge.svg?style=flat-square 19 | [snyk-url]: https://snyk.io/test/npm/egg-http-proxy 20 | [download-image]: https://img.shields.io/npm/dm/egg-http-proxy.svg?style=flat-square 21 | [download-url]: https://npmjs.org/package/egg-http-proxy 22 | 23 | Configure proxy middleware for egg. Use [http-proxy-middleware](https://github.com/chimurai/http-proxy-middleware). 24 | 25 | ## Install 26 | 27 | ```bash 28 | $ npm i egg-http-proxy --save 29 | ``` 30 | 31 | ## Usage 32 | 33 | ```js 34 | // {app_root}/config/plugin.js 35 | exports.httpProxy = { 36 | enable: true, 37 | package: 'egg-http-proxy', 38 | }; 39 | ``` 40 | 41 | ## Configuration 42 | 43 | Proxy `/api` requests to `http://www.example.org`: 44 | 45 | ```js 46 | // {app_root}/config/config.default.js 47 | exports.httpProxy = { 48 | '/api': 'http://www.example.org' 49 | }; 50 | ``` 51 | 52 | A request to `/api/users` will now proxy the request to `http://www.example.org/api/users`. 53 | 54 | If you don't want `/api` to be passed along, we need to rewrite the path: 55 | 56 | ```js 57 | // {app_root}/config/config.default.js 58 | exports.httpProxy = { 59 | '/api': { 60 | target: 'http://www.example.org', 61 | pathRewrite: {'^/api' : ''} 62 | } 63 | }; 64 | ``` 65 | 66 | For more advanced usages, checkout [http-proxy-middleware](https://github.com/chimurai/http-proxy-middleware#options) options documentation. 67 | 68 | ## Questions & Suggestions 69 | 70 | Please open an issue [here](https://github.com/chunkai1312/egg-http-proxy/issues). 71 | 72 | ## License 73 | 74 | [MIT](LICENSE) 75 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = app => { 4 | app.config.coreMiddleware.unshift('httpProxy'); 5 | }; 6 | -------------------------------------------------------------------------------- /app/middleware/http_proxy.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const proxy = require('http-proxy-middleware'); 4 | const c2k = require('koa2-connect'); 5 | const pathMatching = require('egg-path-matching'); 6 | const omit = require('lodash/omit'); 7 | 8 | module.exports = options => { 9 | return async function httpProxy(ctx, next) { 10 | const proxyTable = omit(options, [ 'enable', 'match', 'ignore' ]); 11 | const path = ctx.request.originalUrl || ctx.request.url; 12 | 13 | Object.keys(proxyTable).some(context => { 14 | const match = pathMatching({ match: context }); 15 | const isMatch = match({ path }); 16 | 17 | if (isMatch) { 18 | let proxyOptions = proxyTable[context]; 19 | if (typeof proxyOptions === 'string') { 20 | proxyOptions = { target: proxyOptions }; 21 | } 22 | c2k(proxy(context, proxyOptions))(ctx, next); 23 | } 24 | 25 | return isMatch; 26 | }); 27 | 28 | await next(); 29 | }; 30 | }; 31 | -------------------------------------------------------------------------------- /config/config.default.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * egg-http-proxy default config 5 | * @member Config#httpProxy 6 | * @property {String} SOME_KEY - some description 7 | */ 8 | exports.httpProxy = { 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | import 'egg'; 2 | import * as httpProxyMiddleware from 'http-proxy-middleware'; 3 | 4 | declare module 'egg' { 5 | interface ProxyConfigMap { 6 | [url: string]: string | httpProxyMiddleware.Config; 7 | } 8 | 9 | type ProxyConfigArrayItem = { 10 | path?: string | string[]; 11 | context?: string | string[] | httpProxyMiddleware.Filter; 12 | } & httpProxyMiddleware.Config; 13 | 14 | type ProxyConfigArray = ProxyConfigArrayItem[]; 15 | 16 | interface EggAppConfig { 17 | httpProxy: ProxyConfigMap | ProxyConfigArray; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "egg-http-proxy", 3 | "version": "1.0.1", 4 | "description": "proxy middleware plugin for egg", 5 | "eggPlugin": { 6 | "name": "httpProxy" 7 | }, 8 | "keywords": [ 9 | "egg", 10 | "eggPlugin", 11 | "egg-plugin", 12 | "proxy", 13 | "http-proxy", 14 | "http-proxy-middleware" 15 | ], 16 | "dependencies": { 17 | "egg-path-matching": "^1.0.1", 18 | "http-proxy-middleware": "^0.20.0", 19 | "koa2-connect": "^1.0.2", 20 | "lodash": "^4.17.15" 21 | }, 22 | "devDependencies": { 23 | "autod": "^3.1.0", 24 | "autod-egg": "^1.1.0", 25 | "egg": "^2.26.0", 26 | "egg-bin": "^4.14.0", 27 | "egg-ci": "^1.13.1", 28 | "egg-mock": "^3.25.0", 29 | "egg-path-matching": "^1.0.1", 30 | "eslint": "^6.8.0", 31 | "eslint-config-egg": "^8.0.0", 32 | "express": "^4.17.1", 33 | "http-proxy-middleware": "^0.20.0", 34 | "koa2-connect": "^1.0.2", 35 | "lodash": "^4.17.15", 36 | "webstorm-disable-index": "^1.2.0" 37 | }, 38 | "engines": { 39 | "node": ">=8.0.0" 40 | }, 41 | "scripts": { 42 | "test": "npm run lint -- --fix && egg-bin pkgfiles && npm run test-local", 43 | "test-local": "egg-bin test", 44 | "cov": "egg-bin cov", 45 | "lint": "eslint .", 46 | "ci": "egg-bin pkgfiles --check && npm run lint && npm run cov", 47 | "pkgfiles": "egg-bin pkgfiles", 48 | "autod": "autod" 49 | }, 50 | "files": [ 51 | "app", 52 | "config", 53 | "app.js", 54 | "index.d.ts" 55 | ], 56 | "ci": { 57 | "version": "8, 9" 58 | }, 59 | "repository": { 60 | "type": "git", 61 | "url": "git+https://github.com/chunkai1312/egg-http-proxy.git" 62 | }, 63 | "bugs": { 64 | "url": "https://github.com/chunkai1312/egg-http-proxy/issues" 65 | }, 66 | "homepage": "https://github.com/chunkai1312/egg-http-proxy#readme", 67 | "author": "Chun-Kai Wang ", 68 | "license": "MIT" 69 | } 70 | -------------------------------------------------------------------------------- /test/fixtures/apps/http-proxy-test/app/controller/home.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Controller = require('egg').Controller; 4 | 5 | class HomeController extends Controller { 6 | async index() { 7 | this.ctx.body = 'hi, ' + this.app.plugins.httpProxy.name; 8 | } 9 | } 10 | 11 | module.exports = HomeController; 12 | -------------------------------------------------------------------------------- /test/fixtures/apps/http-proxy-test/app/router.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = app => { 4 | const { router, controller } = app; 5 | 6 | router.get('/', controller.home.index); 7 | }; 8 | -------------------------------------------------------------------------------- /test/fixtures/apps/http-proxy-test/config/config.default.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.keys = '123456'; 4 | 5 | exports.httpProxy = { 6 | '/proxy1': 'http://localhost:3000', 7 | '/api/proxy2': { 8 | target: 'http://localhost:3001', 9 | pathRewrite: { '^/api': '' }, 10 | }, 11 | }; 12 | -------------------------------------------------------------------------------- /test/fixtures/apps/http-proxy-test/config/plugin.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | 5 | exports.httpProxy = { 6 | enable: true, 7 | path: path.join(__dirname, '../../../../../'), 8 | }; 9 | -------------------------------------------------------------------------------- /test/fixtures/apps/http-proxy-test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "http-proxy-test", 3 | "version": "0.0.1" 4 | } -------------------------------------------------------------------------------- /test/http-proxy.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const mock = require('egg-mock'); 4 | const express = require('express'); 5 | 6 | function startProxyServers() { 7 | const listeners = []; 8 | const proxy1 = express(); 9 | const proxy2 = express(); 10 | 11 | proxy1.get('/proxy1', (req, res) => { 12 | res.send('from proxy1'); 13 | }); 14 | 15 | proxy2.get('/proxy2', (req, res) => { 16 | res.send('from proxy2'); 17 | }); 18 | 19 | listeners.push(proxy1.listen(3000)); 20 | listeners.push(proxy2.listen(3001)); 21 | 22 | return function proxy() { 23 | listeners.forEach(listener => { 24 | listener.close(); 25 | }); 26 | }; 27 | } 28 | 29 | describe('test/http-proxy.test.js', () => { 30 | let app; 31 | let closeProxyServers; 32 | 33 | before(() => { 34 | closeProxyServers = startProxyServers(); 35 | app = mock.app({ 36 | baseDir: 'apps/http-proxy-test', 37 | }); 38 | return app.ready(); 39 | }); 40 | 41 | after(() => { 42 | app.close(); 43 | closeProxyServers(); 44 | }); 45 | 46 | afterEach(mock.restore); 47 | 48 | it('should target proxy1', () => { 49 | return app.httpRequest() 50 | .get('/proxy1') 51 | .expect(200, 'from proxy1'); 52 | }); 53 | 54 | it('should target proxy2 with path rewrite', () => { 55 | return app.httpRequest() 56 | .get('/api/proxy2') 57 | .expect(200, 'from proxy2'); 58 | }); 59 | }); 60 | --------------------------------------------------------------------------------