At first I only needed the reverse proxy for a JSON rest API. Soon, however, it was expanded to also cover HTML content. Thus the below update to make sure any URLs in the HTML was replaced to correctly match the reverse proxy server and not the internal server:
public class ProxyHandler : DelegatingHandler { private readonly string redirectUrl; public ProxyHandler(string redirectUrl) { this.redirectUrl = redirectUrl; } private async Task<HttpResponseMessage> RedirectRequest(HttpRequestMessage request, CancellationToken cancellationToken) { var redirectLocation = redirectUrl; var localPath = request.RequestUri.LocalPath.Replace("ExternalVirtualPath", "InternalVirtualPath"); var client = new HttpClient(new HttpClientHandler() { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate }); var clonedRequest = await HttpRequestMessageExtensions.CloneHttpRequestMessageAsync(request); clonedRequest.RequestUri = new Uri(redirectLocation + localPath); var httpResponseMessage = await client.SendAsync(clonedRequest, HttpCompletionOption.ResponseHeadersRead, cancellationToken); httpResponseMessage.Headers.Add("X-ReverseProxy", "true"); if (httpResponseMessage.Content?.Headers?.ContentType != null) { if (httpResponseMessage.Content.Headers.ContentType.MediaType == "text/html") { var content = await httpResponseMessage.Content.ReadAsByteArrayAsync(); var stringContent = Encoding.UTF8.GetString(content); var newContent = stringContent.Replace("InternalVirtualPath", "ExternalVirtualPath"); httpResponseMessage.Content = new StringContent(newContent, Encoding.UTF8, "text/html"); } } return httpResponseMessage; } protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) { return RedirectRequest(request, cancellationToken); } }
Pingback: Reverse Proxy in ASP.NET Web API | Kasper Holdum