an-node-proxy
Advanced tools
Comparing version 1.0.0 to 1.0.1
{ | ||
"name": "an-node-proxy", | ||
"version": "1.0.0", | ||
"version": "1.0.1", | ||
"description": "", | ||
"main": "index.js", | ||
"main": "lib/index.js", | ||
"scripts": { | ||
@@ -7,0 +7,0 @@ "dev": "babel src --watch -d lib", |
# an-node-proxy | ||
`an-node-proxy` is an http proxying library, supports both http and https, and also supports proxy to local data with the need of mock request | ||
`an-node-proxy` is an http proxying library, supports both http and https, and also supports proxy to local data with the need of mock request | ||
## Features | ||
- [x] http proxy | ||
- [x] https proxy | ||
- [x] mock | ||
- [ ] more headers, au and so on | ||
- [ ] improve readme | ||
- [ ] an tool to produce index | ||
## Installation | ||
npm install an-node-proxy --save | ||
## Ussage | ||
### http proxy | ||
```js | ||
import http from 'http' | ||
import {createProxyServer} from 'an-node-proxy' | ||
const proxy = createProxyServer({ | ||
target:'http://localhost:8002' | ||
}).listen(8001); | ||
http.createServer(function (req, res) { | ||
res.write('from 8002') | ||
res.end(); | ||
}).listen(8002); | ||
``` | ||
so does https, `an-node-proxy` also support | ||
### middileware | ||
```js | ||
import express from 'express' | ||
import {join as pathjoin} from 'path' | ||
import {createProxy} from 'an-node-proxy' | ||
const app = new express() | ||
const proxy = createProxy() | ||
app.use((req, res, next) => { | ||
proxy.proxy(req, res, { | ||
target: 'http://www.baidu.com' | ||
}) | ||
next() | ||
}) | ||
app.listen(8000) | ||
``` | ||
### mock | ||
```js | ||
import http from 'http' | ||
import {join as pathjoin} from 'path' | ||
http.createServer(function (req, res) { | ||
proxy.proxy(req, res, { | ||
mock: { | ||
base: pathJoin(__dirname, 'mock'), | ||
rules: [{ | ||
from: '/test/', | ||
to: './' | ||
}] | ||
} | ||
}); | ||
}).listen(8009); | ||
``` |
@@ -7,17 +7,28 @@ import {createServer} from 'http' | ||
export default class HttpProxy extends EventEmitter{ | ||
constructor(options) { | ||
constructor(option, server) { | ||
super() | ||
this.options = options | ||
if (options) { | ||
this.option = this.adaptMock(option) | ||
if (server) { | ||
this.server = createServer((req, res) => { | ||
this.req = req | ||
this.res = res | ||
this.proxy(req, res, option, this) | ||
}) | ||
} | ||
} | ||
this.proxy(req, res, options, this) | ||
adaptoption(option) { | ||
if (!option.target) { | ||
} | ||
this.adaptMock(option) | ||
this.adaptTarget(option) | ||
return option | ||
} | ||
adaptTarget(options) { | ||
if (!options.target) { | ||
adaptTarget(option) { | ||
if (!option.target) { | ||
return | ||
@@ -33,3 +44,3 @@ } | ||
} | ||
let urlInfo = typeof options.target === 'string' ? new URL(options.target) : options.target | ||
let urlInfo = typeof option.target === 'string' ? new URL(option.target) : option.target | ||
@@ -40,12 +51,12 @@ for (const key of Object.keys(target)) { | ||
options.target = target | ||
option.target = target | ||
} | ||
adaptMock(options) { | ||
if (!options.mock) { | ||
adaptMock(option) { | ||
if (!option.mock) { | ||
return; | ||
} | ||
const mock = options.mock | ||
const base = mock.base || optionsprocess.cwd() | ||
const mock = option.mock | ||
const base = mock.base || process.cwd() | ||
const rules = mock.rules | ||
@@ -60,3 +71,3 @@ | ||
options.rules = {base, rules} | ||
option.rules = {base, rules} | ||
} | ||
@@ -72,12 +83,19 @@ | ||
//供中间件使用的代理函数 | ||
proxy(req, res, options) { | ||
this.adaptTarget(options) | ||
this.adaptMock(options) | ||
handleInCommingMsg(req, res, options, this) | ||
proxy(req, res, option) { | ||
if (option) { | ||
this.adaptoption(option) | ||
} | ||
handleInCommingMsg(req, res, option, this) | ||
} | ||
listen(port) { | ||
this.server.listen(port) | ||
this.server.listen(port, e => { | ||
if (e) { | ||
return console.error(e) | ||
} | ||
console.log(`proxy server is on http://localhost:${port}`) | ||
}) | ||
return this | ||
} | ||
} |
@@ -6,76 +6,93 @@ import http from 'http' | ||
import {excuteFunc} from './common' | ||
import {hostname} from 'os' | ||
export default function(req, res, options, server) { | ||
const mockFilename = matchMock(req, options) | ||
console.log(mockFilename) | ||
if (!mockFilename && options.target) { | ||
proxyRequest(req, res, options, server) | ||
} else if (mockFilename && statSync(mockFilename).isFile()) { | ||
const responseJson = require(mockFilename) || require(mockFilename).default | ||
res.setHeader('Content-type', 'Application/json') | ||
res.write(JSON.stringify(responseJson)) | ||
res.end() | ||
} else { | ||
res.writeHead(404, {'Content-type': 'text/html; charset=gbk'}) | ||
res.end(`options target未指定且${mockFilename}不存在`) | ||
function matchMock(req, option) { | ||
const relUrl = req.url | ||
const mock = option.mock | ||
let mockJsonLoc = false | ||
if (mock && mock.rules && mock.rules !== 0) { | ||
mock.rules.every(rule => { | ||
const from = rule.from | ||
if (relUrl.indexOf(from) === 0) { | ||
mockJsonLoc = rule.to + relUrl.substring(rule.from.length, relUrl.length) | ||
return false | ||
} | ||
return true | ||
}) | ||
} | ||
return mockJsonLoc ? resolve(mock.base, mockJsonLoc) : false | ||
} | ||
function matchMock(req, options) { | ||
const relUrl = req.url | ||
const mock = options.mock | ||
let mockJsonLoc = false | ||
if (mock && mock.rules && mock.rules !== 0) { | ||
mock.rules.every(rule => { | ||
const from = rule.from | ||
if (relUrl.indexOf(from) === 0) { | ||
mockJsonLoc = rule.to + relUrl.substring(rule.from.length, relUrl.length) | ||
return false | ||
} | ||
function proxyRequest(req, res, option, server) { | ||
const requestOption = parseRequestOption(req, option) | ||
const request = requestOption.protocol === 'https:' ? https.request : http.request | ||
return true | ||
}) | ||
const proxyReq = request(requestOption, proxyRes => { | ||
server.emit('proxyRes', {res, req, proxyRes, option}) | ||
writeHeaders(res, proxyRes) | ||
proxyRes.pipe(res) | ||
}) | ||
proxyReq.on('error', e => { | ||
if (e.code === 'ETIMEDOUT') { | ||
console.error(e.message) | ||
} | ||
return mockJsonLoc ? resolve(mock.base, mockJsonLoc) : false | ||
} | ||
server.emit('error', {e, req, res}) | ||
}) | ||
function proxyRequest(req, res, options, server) { | ||
const requestOptions = parseRequestOptions(req, options) | ||
const request = requestOptions.protocol === 'https:' ? https.request : http.request | ||
const proxyReq = request(requestOptions, proxyRes => { | ||
// proxyRes.on('end', () => { | ||
// res.end() | ||
// }); | ||
server.emit('proxyRes', {res, req, proxyRes, options}) | ||
excuteFunc(options.before, proxyRes, res, ) | ||
writeHeaders(res, proxyRes) | ||
proxyRes.pipe(res) | ||
}) | ||
req.on('error', e => { | ||
console.log(e) | ||
}) | ||
proxyReq.on('error', errorHandler) | ||
proxyReq.end() | ||
} | ||
req.on('error', errorHandler) | ||
proxyReq.end() | ||
function parseRequestOption(req, option) { | ||
let path = req.url | ||
let {host, hostname, protocol, port} = option.target | ||
let {headers, method} = req | ||
headers.host = hostname | ||
if (option.headers) { | ||
headers = Object.assign({}, headers, option.headers) | ||
} | ||
function errorHandler(e) { | ||
server.emit('error', e, req, res) | ||
if (option.method) { | ||
method = option.method | ||
} | ||
function parseRequestOptions(req, options) { | ||
let path = req.url | ||
let {host, hostname, protocol, port} = options.target | ||
let {method, headers} = req | ||
headers.host = hostname | ||
return Object.assign({}, {host, hostname, protocol, port, path}, {method, headers}) | ||
return Object.assign({}, {host, hostname, protocol, port, path}, {method, headers}) | ||
} | ||
function writeHeaders(res, proxyRes) { | ||
for (let [key, header] of Object.entries(proxyRes.headers)) { | ||
res.setHeader(key, header) | ||
} | ||
function writeHeaders(res, proxyRes) { | ||
for (let [key, header] of Object.entries(proxyRes.headers)) { | ||
res.setHeader(key, header) | ||
const {statusCode, statusMessage} = proxyRes | ||
res.writeHead(statusCode, statusMessage) | ||
} | ||
export default function(req, res, option, server) { | ||
const mockFilename = matchMock(req, option) | ||
if (!mockFilename && option.target) { | ||
return proxyRequest(req, res, option, server) | ||
} else if (mockFilename) { | ||
let responseJson = null | ||
try { | ||
responseJson = require(mockFilename) || require(mockFilename).default | ||
} catch (e) { | ||
responseJson = `mock file dest: ${mockFilename} is not exsited` | ||
console.error(responseJson) | ||
} | ||
const {statusCode, statusMessage} = proxyRes | ||
res.writeHead(statusCode, statusMessage) | ||
res.setHeader('Content-type', 'Application/json') | ||
res.write(JSON.stringify(responseJson)) | ||
return res.end() | ||
} | ||
res.writeHead(404, {'Content-type': 'text/html; charset=utf-8'}) | ||
res.end(`option.target is expected a url but got ${option.target}`) | ||
} |
import HttpProxy from './http-proxy' | ||
export function createServer (options) { | ||
return new HttpProxy(options) | ||
/** | ||
* option = { | ||
* target: string, target url, | ||
* headers: [{key: value}, {key, value}], //headers will be assigned to requestHeaders | ||
* mock: { | ||
* base: string, //local base dir, default to cwd | ||
* rules: [{ | ||
* from: string, // mock from, such as, '/test/', | ||
* to: string, // mock to, such as, '/dest/' //when this rule works, the '/test/a.js' will be proxyed to `${base}/dest/a.js` | ||
* }, ...] | ||
* } | ||
* } | ||
*/ | ||
export function createProxyServer (option) { | ||
return new HttpProxy(option, true) | ||
} | ||
export function createProxyServer() { | ||
return new HttpProxy() | ||
export function createProxy(option) { | ||
return new HttpProxy(option, false) | ||
} | ||
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
19591
463
68
11
7
7