Skip to content

Commit

Permalink
More docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Tratcher committed Oct 8, 2020
1 parent 3374c37 commit 26bf2fa
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 29 deletions.
50 changes: 24 additions & 26 deletions docs/docfx/articles/direct-proxing.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ title: Direct Proxying

# Direct Proxying

Introduced: preview6

Some applications only need the ability to take a specific request and proxy it to a specific destination. These applications do not need, or have addressed in other ways, the other features of the proxy like configuration discovery, routing, load balancing, etc..

## IHttpProxy

IHttpProxy serves as the core proxy adapter between AspNetCore and HttpClient. It handles the mechanics of creating a HttpRequestMessage from an HttpContext, sending it, and relaying the response.
[IHttpProxy](xref:Microsoft.ReverseProxy.Service.Proxy.IHttpProxy) serves as the core proxy adapter between incoming AspNetCore and outgoing System.Net.Http requests. It handles the mechanics of creating a HttpRequestMessage from a HttpContext, sending it, and relaying the response.

IHttpProxy supports:
- Dynamic destination selection, you specify the destination for each request.
Expand All @@ -18,22 +20,22 @@ IHttpProxy supports:
- Error handling

It does not include:
- Load balancing
- Routing
- Retries
- Load balancing
- Affinity
- Retries

## Example

### Create a new project

Follow the [Getting Started](xref:getting_started.md) guide to create a project and add the Microsoft.ReverseProxy nuget dependency.
Follow the [Getting Started](xref:getting_started) guide to create a project and add the Microsoft.ReverseProxy nuget dependency.

### Update Startup

In this example the IHttpProxy is registered in DI, injected into the `Startup.Configure` method, and used to proxy requests from a specific route to `https://localhost:10000/`.

The optional transforms show how to copy all request headers except for the `Host` as the destination may require its own `Host` from the url.
The optional transforms show how to copy all request headers except for the `Host`, it's common that the destination requires its own `Host` from the url.

```C#
public void ConfigureServices(IServiceCollection services)
Expand All @@ -59,7 +61,8 @@ public void Configure(IApplicationBuilder app, IHttpProxy httpProxy)
requestTransforms: Array.Empty<RequestParametersTransform>(),
requestHeaderTransforms: new Dictionary<string, RequestHeaderTransform>()
{
{ HeaderNames.Host, new RequestHeaderValueTransform(string.Empty, append: false) }
{ HeaderNames.Host,
new RequestHeaderValueTransform(string.Empty, append: false) }
},
responseHeaderTransforms: new Dictionary<string, ResponseHeaderTransform>(),
responseTrailerTransforms: new Dictionary<string, ResponseHeaderTransform>())
Expand All @@ -69,39 +72,34 @@ public void Configure(IApplicationBuilder app, IHttpProxy httpProxy)
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
await httpProxy.ProxyAsync(httpContext, "https://localhost:10000/", httpClient, proxyOptions);
var errorFeature = httpContext.Features.Get<IProxyErrorFeature>();
if (errorFeature != null)
endpoints.Map("/{**catch-all}", async httpContext =>
{
var error = errorFeature.Error;
var exception = errorFeature.Exception;
}
await httpProxy.ProxyAsync(
httpContext, "https://localhost:10000/", httpClient, proxyOptions);

var errorFeature = httpContext.Features.Get<IProxyErrorFeature>();
if (errorFeature != null)
{
var error = errorFeature.Error;
var exception = errorFeature.Exception;
}
});
});
}
```

### The HTTP Client

The http client may be customized, but the following example is recommended for common proxy scenarios:

```C#
var httpClient = new HttpMessageInvoker(new SocketsHttpHandler()
{
UseProxy = false,
AllowAutoRedirect = false,
AutomaticDecompression = DecompressionMethods.None,
UseCookies = false
});
```
The http client may be customized, but the above example is recommended for common proxy scenarios.

Always use HttpMessageInvoker rather than HttpClient. See https://github.com/microsoft/reverse-proxy/issues/458 for details.
Always use HttpMessageInvoker rather than HttpClient, HttpClient buffers responses by default. Buffering breaks streaming scenarios and increases memory usage and latency.

Re-using a client for requests to the same destination is recommended for performance reasons as it allows you to re-use pooled connections. A client may also be re-used for requests to different destinations if the configuration is the same.

### Transforms

The request and response can be modified by providing [transforms](xref:transforms.md) on the RequestProxyOptions.
The request and response can be modified by providing [transforms](transforms.md) on the [RequestProxyOptions](xref:Microsoft.ReverseProxy.Service.Proxy.RequestProxyOptions).

### Error handling

IHttpProxy catches client exceptions and timeouts, logs them, and converts them to 5xx status codes or aborts the response. The error details, if any, can be accessed from the IProxyErrorFeature as shown above.
IHttpProxy catches exceptions and timeouts from the HTTP client, logs them, and converts them to 5xx status codes or aborts the response. The error details, if any, can be accessed from the [IProxyErrorFeature](xref:Microsoft.ReverseProxy.Service.Proxy.IProxyErrorFeature) as shown above.
6 changes: 6 additions & 0 deletions samples/ReverseProxy.Direct.Sample/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ public void Configure(IApplicationBuilder app, IHttpProxy httpProxy)
endpoints.Map("/{**catch-all}", async httpContext =>
{
await httpProxy.ProxyAsync(httpContext, "https://localhost:10000/", httpClient, proxyOptions);
var errorFeature = httpContext.Features.Get<IProxyErrorFeature>();
if (errorFeature != null)
{
var error = errorFeature.Error;
var exception = errorFeature.Exception;
}
});
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Microsoft.ReverseProxy.Abstractions
public enum HeaderMatchMode
{
/// <summary>
/// The header must match in its entirety, subject to the value of <see cref="IHeaderMetadata.IsCaseSensitive"/>.
/// The header must match in its entirety, subject to case sensitivity settings.
/// Only single headers are supported. If there are multiple headers with the same name then the match fails.
/// </summary>
ExactHeader,
Expand All @@ -22,7 +22,7 @@ public enum HeaderMatchMode
// ValuePrefix,

/// <summary>
/// The header must match by prefix, subject to the value of <see cref="IHeaderMetadata.IsCaseSensitive"/>.
/// The header must match by prefix, subject to case sensitivity settings.
/// Only single headers are supported. If there are multiple headers with the same name then the match fails.
/// </summary>
HeaderPrefix,
Expand Down
4 changes: 4 additions & 0 deletions src/ReverseProxy/Service/Proxy/IHttpProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ public interface IHttpProxy
/// <summary>
/// Proxies the incoming request to the destination server, and the response back to the client.
/// </summary>
/// <param name="context">The HttpContent to proxy from.</param>
/// <param name="destinationPrefix">The url prefix for where to proxy the request to.</param>
/// <param name="httpClient">The HTTP client used to send the proxy request.</param>
/// <param name="proxyOptions">Options for this operation.</param>
Task ProxyAsync(
HttpContext context,
string destinationPrefix,
Expand Down
8 changes: 7 additions & 1 deletion src/ReverseProxy/Service/Proxy/RequestProxyOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,19 @@

namespace Microsoft.ReverseProxy.Service.Proxy
{
/// <summary>
/// Options for <see cref="IHttpProxy.ProxyAsync"/>
/// </summary>
public class RequestProxyOptions
{
/// <summary>
/// Optional transforms for modifying the request and response.
/// </summary>
public Transforms Transforms { get; set; } = Transforms.Empty;

/// <summary>
/// The time allowed to send the request and receive the response headers. This may include
/// the time needed to send the request body.
/// the time needed to send the request body. The default is 100 seconds.
/// </summary>
public TimeSpan RequestTimeout { get; set; } = TimeSpan.FromSeconds(100);

Expand Down

0 comments on commit 26bf2fa

Please sign in to comment.