2.2.0
This commit is contained in:
parent
49ea99ed6c
commit
daca263062
7 changed files with 54 additions and 35 deletions
|
@ -1,3 +1,9 @@
|
|||
# 2.2.0
|
||||
* Use `http.Client` instead of `http.BaseClient`, and make it an
|
||||
optional parameter.
|
||||
* Allow `baseUrl` to accept `Uri` or `String`.
|
||||
* Add `Proxy.pushState`.
|
||||
|
||||
# 2.1.2
|
||||
* Apply lints.
|
||||
|
||||
|
|
13
README.md
13
README.md
|
@ -10,12 +10,9 @@ import 'package:angel_proxy/angel_proxy.dart';
|
|||
import 'package:http/http.dart' as http;
|
||||
|
||||
main() async {
|
||||
// ...
|
||||
|
||||
var client = http.Client();
|
||||
|
||||
// Forward requests instead of serving statically
|
||||
var proxy1 = Proxy(client, Uri.parse('http://localhost:3000'));
|
||||
// Forward requests instead of serving statically.
|
||||
// You can also pass a URI, instead of a string.
|
||||
var proxy1 = Proxy('http://localhost:3000');
|
||||
|
||||
// handle all methods (GET, POST, ...)
|
||||
app.fallback(proxy.handleRequest);
|
||||
|
@ -24,12 +21,12 @@ main() async {
|
|||
|
||||
You can also restrict the proxy to serving only from a specific root:
|
||||
```dart
|
||||
Proxy(client, baseUrl, publicPath: '/remote');
|
||||
Proxy(baseUrl, publicPath: '/remote');
|
||||
```
|
||||
|
||||
Also, you can map requests to a root path on the remote server:
|
||||
```dart
|
||||
Proxy(client, baseUrl.replace(path: '/path'));
|
||||
Proxy(baseUrl.replace(path: '/path'));
|
||||
```
|
||||
|
||||
Request bodies will be forwarded as well, if they are not empty. This allows things like POST requests to function.
|
||||
|
|
|
@ -2,20 +2,17 @@ import 'dart:io';
|
|||
import 'package:angel_framework/angel_framework.dart';
|
||||
import 'package:angel_framework/http.dart';
|
||||
import 'package:angel_proxy/angel_proxy.dart';
|
||||
import 'package:http/io_client.dart' as http;
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
final Duration timeout = Duration(seconds: 5);
|
||||
|
||||
main() async {
|
||||
var app = Angel();
|
||||
var client = http.IOClient();
|
||||
|
||||
// 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 = Proxy(
|
||||
client,
|
||||
Uri.parse('https://pub.dartlang.org'),
|
||||
'https://pub.dartlang.org',
|
||||
publicPath: '/pub',
|
||||
timeout: timeout,
|
||||
);
|
||||
|
@ -25,8 +22,7 @@ main() async {
|
|||
//
|
||||
// Play around with this at http://www.websocket.org/echo.html.
|
||||
var echoProxy = Proxy(
|
||||
client,
|
||||
Uri.parse('http://echo.websocket.org'),
|
||||
'http://echo.websocket.org',
|
||||
publicPath: '/echo',
|
||||
timeout: timeout,
|
||||
);
|
||||
|
@ -40,8 +36,7 @@ main() async {
|
|||
|
||||
// Anything else should fall through to dartlang.org.
|
||||
var dartlangProxy = Proxy(
|
||||
client,
|
||||
Uri.parse('https://dartlang.org'),
|
||||
'https://dartlang.org',
|
||||
timeout: timeout,
|
||||
recoverFrom404: false,
|
||||
);
|
||||
|
|
|
@ -10,10 +10,14 @@ import 'package:path/path.dart' as p;
|
|||
final RegExp _straySlashes = RegExp(r'(^/+)|(/+$)');
|
||||
final MediaType _fallbackMediaType = MediaType('application', 'octet-stream');
|
||||
|
||||
/// A middleware class that forwards requests (reverse proxies) to an upstream server.
|
||||
///
|
||||
/// Supports WebSockets, in addition to regular HTTP requests.
|
||||
class Proxy {
|
||||
String _prefix;
|
||||
|
||||
final http.BaseClient httpClient;
|
||||
/// The underlying [Client] to use.
|
||||
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.
|
||||
final bool recoverFromDead;
|
||||
|
@ -25,26 +29,53 @@ class Proxy {
|
|||
final Duration timeout;
|
||||
|
||||
Proxy(
|
||||
this.httpClient,
|
||||
this.baseUrl, {
|
||||
baseUrl, {
|
||||
http.Client httpClient,
|
||||
this.publicPath = '/',
|
||||
this.recoverFromDead = true,
|
||||
this.recoverFrom404 = true,
|
||||
this.timeout,
|
||||
}) {
|
||||
if (!baseUrl.hasScheme || !baseUrl.hasAuthority)
|
||||
}) : this.baseUrl = baseUrl is Uri ? baseUrl : Uri.parse(baseUrl.toString()),
|
||||
this.httpClient = httpClient ?? http.Client() {
|
||||
if (!this.baseUrl.hasScheme || !this.baseUrl.hasAuthority) {
|
||||
throw ArgumentError(
|
||||
'Invalid `baseUrl`. URI must have both a scheme and authority.');
|
||||
if (this.recoverFromDead == null)
|
||||
}
|
||||
if (this.recoverFromDead == null) {
|
||||
throw ArgumentError.notNull("recoverFromDead");
|
||||
if (this.recoverFrom404 == null)
|
||||
}
|
||||
if (this.recoverFrom404 == null) {
|
||||
throw ArgumentError.notNull("recoverFrom404");
|
||||
}
|
||||
|
||||
_prefix = publicPath?.replaceAll(_straySlashes, '') ?? '';
|
||||
}
|
||||
|
||||
void close() => httpClient.close();
|
||||
|
||||
/// A handler that serves the file at the given path, unless the user has requested that path.
|
||||
///
|
||||
/// You can also limit this functionality to specific values of the `Accept` header, ex. `text/html`.
|
||||
/// If [accepts] is `null`, OR at least one of the content types in [accepts] is present,
|
||||
/// the view will be served.
|
||||
RequestHandler pushState(String path, {Iterable accepts}) {
|
||||
var vPath = path.replaceAll(_straySlashes, '');
|
||||
if (_prefix?.isNotEmpty == true) vPath = '$_prefix/$vPath';
|
||||
|
||||
return (RequestContext req, ResponseContext res) {
|
||||
var path = req.path.replaceAll(_straySlashes, '');
|
||||
if (path == vPath) return Future<bool>.value(true);
|
||||
|
||||
if (accepts?.isNotEmpty == true) {
|
||||
if (!accepts.any((x) => req.accepts(x, strict: true))) {
|
||||
return Future<bool>.value(true);
|
||||
}
|
||||
}
|
||||
|
||||
return servePath(vPath, req, res);
|
||||
};
|
||||
}
|
||||
|
||||
/// Handles an incoming HTTP request.
|
||||
Future<bool> handleRequest(RequestContext req, ResponseContext res) {
|
||||
var path = req.path.replaceAll(_straySlashes, '');
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
name: angel_proxy
|
||||
description: Angel middleware to forward requests to another server (i.e. pub serve).
|
||||
version: 2.1.2
|
||||
version: 2.2.0
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/proxy
|
||||
environment:
|
||||
|
|
|
@ -17,12 +17,10 @@ main() {
|
|||
setUp(() async {
|
||||
app = Angel();
|
||||
var appHttp = AngelHttp(app);
|
||||
var httpClient = http.IOClient();
|
||||
|
||||
testServer = await startTestServer();
|
||||
|
||||
var proxy1 = Proxy(
|
||||
httpClient,
|
||||
Uri(
|
||||
scheme: 'http',
|
||||
host: testServer.address.address,
|
||||
|
@ -30,7 +28,7 @@ main() {
|
|||
publicPath: '/proxy',
|
||||
);
|
||||
|
||||
var proxy2 = Proxy(httpClient, proxy1.baseUrl.replace(path: '/foo'));
|
||||
var proxy2 = Proxy(proxy1.baseUrl.replace(path: '/foo'));
|
||||
print('Proxy 1 on: ${proxy1.baseUrl}');
|
||||
print('Proxy 2 on: ${proxy2.baseUrl}');
|
||||
|
||||
|
@ -42,10 +40,6 @@ main() {
|
|||
res.write('intercept empty');
|
||||
});
|
||||
|
||||
app.shutdownHooks.add((_) async {
|
||||
httpClient.close();
|
||||
});
|
||||
|
||||
app.logger = Logger('angel');
|
||||
|
||||
Logger.root.onRecord.listen((rec) {
|
||||
|
|
|
@ -4,7 +4,6 @@ import 'package:angel_framework/angel_framework.dart';
|
|||
import 'package:angel_framework/http.dart';
|
||||
import 'package:angel_proxy/angel_proxy.dart';
|
||||
import 'package:angel_test/angel_test.dart';
|
||||
import 'package:http/io_client.dart' as http;
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:mock_request/mock_request.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
@ -37,10 +36,7 @@ main() {
|
|||
});
|
||||
app.get('/bar', (req, res) => res.write('normal'));
|
||||
|
||||
var httpClient = http.IOClient();
|
||||
|
||||
layer = Proxy(
|
||||
httpClient,
|
||||
Uri(scheme: 'http', host: server.address.address, port: server.port),
|
||||
publicPath: '/proxy',
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue