commit
9ff915a105
5 changed files with 24 additions and 23 deletions
17
README.md
17
README.md
|
@ -2,7 +2,7 @@
|
|||
[![Pub](https://img.shields.io/pub/v/angel_proxy.svg)](https://pub.dartlang.org/packages/angel_proxy)
|
||||
[![build status](https://travis-ci.org/angel-dart/proxy.svg)](https://travis-ci.org/angel-dart/proxy)
|
||||
|
||||
Angel middleware to forward requests to another server (i.e. `pub serve`).
|
||||
Angel middleware to forward requests to another server (i.e. `webdev serve`).
|
||||
|
||||
```dart
|
||||
import 'package:angel_proxy/angel_proxy.dart';
|
||||
|
@ -11,23 +11,26 @@ import 'package:http/http.dart' as http;
|
|||
main() async {
|
||||
// ...
|
||||
|
||||
var client = new http.Client();
|
||||
var proxy = new Proxy(app, client, 'http://localhost:3000');
|
||||
var client = http.Client();
|
||||
|
||||
// Forward requests instead of serving statically
|
||||
app.use(proxy.handleRequest);
|
||||
var proxy1 = Proxy(client, 'http://localhost:3000');
|
||||
// or split: Proxy(client, 'localhost', port: 8080, protocol: 'http');
|
||||
|
||||
// handle all methods (GET, POST, ...)
|
||||
app.all('*', proxy.handleRequest);
|
||||
}
|
||||
```
|
||||
|
||||
You can also restrict the proxy to serving only from a specific root:
|
||||
```dart
|
||||
new Proxy(app, client, '<host>', publicPath: '/remote');
|
||||
Proxy(client, '<host>', publicPath: '/remote');
|
||||
```
|
||||
|
||||
Also, you can map requests to a root path on the remote server
|
||||
```dart
|
||||
new Proxy(app, client, '<host>', mapTo: '/path');
|
||||
Proxy(client, '<host>', mapTo: '/path');
|
||||
```
|
||||
|
||||
If your app's `storeOriginalBuffer` is `true`, then request bodies will be forwarded
|
||||
If your app's `keepRawRequestBuffers` is `true`, then request bodies will be forwarded
|
||||
as well, if they are not empty. This allows things like POST requests to function.
|
||||
|
|
|
@ -14,7 +14,6 @@ main() async {
|
|||
// Forward any /api requests to pub.
|
||||
// By default, if the host throws a 404, the request will fall through to the next handler.
|
||||
var pubProxy = new Proxy(
|
||||
app,
|
||||
client,
|
||||
'https://pub.dartlang.org',
|
||||
publicPath: '/pub',
|
||||
|
@ -30,7 +29,6 @@ main() async {
|
|||
|
||||
// Anything else should fall through to dartlang.org.
|
||||
var dartlangProxy = new Proxy(
|
||||
app,
|
||||
client,
|
||||
'https://dartlang.org',
|
||||
timeout: timeout,
|
||||
|
|
|
@ -11,7 +11,6 @@ final MediaType _fallbackMediaType = MediaType('application', 'octet-stream');
|
|||
class Proxy {
|
||||
String _prefix;
|
||||
|
||||
final Angel app;
|
||||
final http.Client httpClient;
|
||||
|
||||
/// If `true` (default), then the plug-in will ignore failures to connect to the proxy, and allow other handlers to run.
|
||||
|
@ -25,7 +24,6 @@ class Proxy {
|
|||
final Duration timeout;
|
||||
|
||||
Proxy(
|
||||
this.app,
|
||||
this.httpClient,
|
||||
this.host, {
|
||||
this.port,
|
||||
|
@ -69,7 +67,7 @@ class Proxy {
|
|||
url = url.replaceAll(_straySlashes, '');
|
||||
url = '$url/$mapping';
|
||||
|
||||
if (!url.startsWith('http')) url = 'http://$url';
|
||||
if (!url.startsWith(protocol)) url = '$protocol://$url';
|
||||
url = url.replaceAll(_straySlashes, '');
|
||||
|
||||
var headers = <String, String>{
|
||||
|
@ -88,7 +86,7 @@ class Proxy {
|
|||
|
||||
var body;
|
||||
|
||||
if (req.method != 'GET' && app.keepRawRequestBuffers == true) {
|
||||
if (req.method != 'GET' && req.app.keepRawRequestBuffers == true) {
|
||||
body = (await req.parse()).originalBuffer;
|
||||
}
|
||||
|
||||
|
@ -140,19 +138,24 @@ class Proxy {
|
|||
mediaType = _fallbackMediaType;
|
||||
}
|
||||
|
||||
var proxiedHeaders = new Map<String, String>.from(rs.headers);
|
||||
/// if [http.Client] does not provide us with a content length
|
||||
/// OR [http.Client] is about to decode the response (bytecount returned by [http.Response].stream != known length)
|
||||
/// then we can not provide a value downstream => set to '-1' for 'unspecified length'
|
||||
var isContentLengthUnknown = rs.contentLength == null ||
|
||||
rs.headers[HttpHeaders.contentEncodingHeader]?.isNotEmpty == true ||
|
||||
rs.headers[HttpHeaders.transferEncodingHeader]?.isNotEmpty == true;
|
||||
|
||||
var proxiedHeaders = new Map<String, String>.from(rs.headers)
|
||||
..remove(HttpHeaders.contentEncodingHeader) // drop, http.Client has decoded
|
||||
..remove(HttpHeaders.transferEncodingHeader) // drop, http.Client has decoded
|
||||
..[HttpHeaders.contentLengthHeader] = "${isContentLengthUnknown ? '-1' : rs.contentLength}";
|
||||
|
||||
res
|
||||
..contentType = mediaType
|
||||
..statusCode = rs.statusCode
|
||||
..headers.addAll(proxiedHeaders);
|
||||
|
||||
var stream = rs.stream;
|
||||
|
||||
// [upgrading to dart2] Keeping this workaround as a reference. It's not properly typed for dart2
|
||||
//if (rs.headers[HttpHeaders.contentEncodingHeader] == 'gzip') stream = stream.transform(gzip.encoder);
|
||||
|
||||
await stream.pipe(res);
|
||||
await rs.stream.pipe(res);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -22,14 +22,12 @@ main() {
|
|||
testServer = await startTestServer();
|
||||
|
||||
var proxy1 = new Proxy(
|
||||
app,
|
||||
httpClient,
|
||||
testServer.address.address,
|
||||
port: testServer.port,
|
||||
publicPath: '/proxy',
|
||||
);
|
||||
var proxy2 = new Proxy(
|
||||
app,
|
||||
httpClient,
|
||||
testServer.address.address,
|
||||
port: testServer.port,
|
||||
|
|
|
@ -34,7 +34,6 @@ main() {
|
|||
var httpClient = new http.Client();
|
||||
|
||||
layer = new Proxy(
|
||||
app,
|
||||
httpClient,
|
||||
server.address.address,
|
||||
port: server.port,
|
||||
|
|
Loading…
Reference in a new issue