-
Notifications
You must be signed in to change notification settings - Fork 863
/
Copy pathStartup.cs
126 lines (110 loc) · 6.22 KB
/
Startup.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.Diagnostics;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Yarp.ReverseProxy.Forwarder;
using Yarp.ReverseProxy.Transforms;
namespace Yarp.Sample
{
/// <summary>
/// ASP.NET Core pipeline initialization showing how to use IHttpForwarder to directly handle forwarding requests.
/// With this approach you are responsible for destination discovery, load balancing, and related concerns.
/// </summary>
public class Startup
{
/// <summary>
/// This method gets called by the runtime. Use this method to add services to the container.
/// </summary>
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpForwarder();
}
/// <summary>
/// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
/// </summary>
public void Configure(IApplicationBuilder app, IHttpForwarder forwarder)
{
// Configure our own HttpMessageInvoker for outbound calls for proxy operations
var httpClient = new HttpMessageInvoker(new SocketsHttpHandler()
{
UseProxy = false,
AllowAutoRedirect = false,
AutomaticDecompression = DecompressionMethods.None,
UseCookies = false,
ActivityHeadersPropagator = new ReverseProxyPropagator(DistributedContextPropagator.Current),
ConnectTimeout = TimeSpan.FromSeconds(15),
});
// Setup our own request transform class
var transformer = new CustomTransformer(); // or HttpTransformer.Default;
var requestOptions = new ForwarderRequestConfig { ActivityTimeout = TimeSpan.FromSeconds(100) };
app.UseRouting();
// When using IHttpForwarder for direct forwarding you are responsible for routing, destination discovery, load balancing, affinity, etc..
// For an alternate example that includes those features see BasicYarpSample.
app.UseEndpoints(endpoints =>
{
endpoints.Map("/test/{**catch-all}", async httpContext =>
{
var error = await forwarder.SendAsync(httpContext, "https://example.com", httpClient, requestOptions,
static (context, proxyRequest) =>
{
// Customize the query string:
var queryContext = new QueryTransformContext(context.Request);
queryContext.Collection.Remove("param1");
queryContext.Collection["area"] = "xx2";
// Assign the custom uri. Be careful about extra slashes when concatenating here. RequestUtilities.MakeDestinationAddress is a safe default.
proxyRequest.RequestUri = RequestUtilities.MakeDestinationAddress("https://example.com", context.Request.Path, queryContext.QueryString);
// Suppress the original request header, use the one from the destination Uri.
proxyRequest.Headers.Host = null;
return default;
});
// Check if the proxy operation was successful
if (error != ForwarderError.None)
{
var errorFeature = httpContext.Features.Get<IForwarderErrorFeature>();
var exception = errorFeature.Exception;
}
});
// When using extension methods for registering IHttpForwarder providing configuration, transforms, and HttpMessageInvoker is optional (defaults will be used).
endpoints.MapForwarder("/{**catch-all}", "https://example.com", requestOptions, transformer, httpClient);
});
}
/// <summary>
/// Custom request transformation
/// </summary>
private class CustomTransformer : HttpTransformer
{
/// <summary>
/// A callback that is invoked prior to sending the proxied request. All HttpRequestMessage
/// fields are initialized except RequestUri, which will be initialized after the
/// callback if no value is provided. The string parameter represents the destination
/// URI prefix that should be used when constructing the RequestUri. The headers
/// are copied by the base implementation, excluding some protocol headers like HTTP/2
/// pseudo headers (":authority").
/// </summary>
/// <param name="httpContext">The incoming request.</param>
/// <param name="proxyRequest">The outgoing proxy request.</param>
/// <param name="destinationPrefix">The uri prefix for the selected destination server which can be used to create
/// the RequestUri.</param>
public override async ValueTask TransformRequestAsync(HttpContext httpContext, HttpRequestMessage proxyRequest, string destinationPrefix, CancellationToken cancellationToken)
{
// Copy all request headers
await base.TransformRequestAsync(httpContext, proxyRequest, destinationPrefix, cancellationToken);
// Customize the query string:
var queryContext = new QueryTransformContext(httpContext.Request);
queryContext.Collection.Remove("param1");
queryContext.Collection["area"] = "xx2";
// Assign the custom uri. Be careful about extra slashes when concatenating here. RequestUtilities.MakeDestinationAddress is a safe default.
proxyRequest.RequestUri = RequestUtilities.MakeDestinationAddress("https://example.com", httpContext.Request.Path, queryContext.QueryString);
// Suppress the original request header, use the one from the destination Uri.
proxyRequest.Headers.Host = null;
}
}
}
}