我正在学习ASP.NET Core,为此我正在尝试实现一个简单的代理服务器。 设置理念: 我将浏览器的代理设置设置为指向我的服务器(当前为localhost)。服务器将复制http请求并发送到目标服务器并接收请求。然后将编辑原始响应头以匹配来自实际请求的接收头并发送到客户端。 示例:我在浏览器中输入http://bing.com - >代理设置会将此请求发送到我的服务器 - >我将创建一个名为tempRequest的http请求,其中包含原始请求中的值 - >发送tempRequest并从http://bing.com收到tempResponse - >我将编辑原始的Http响应以匹配tempResponse - >将修改后的响应发送到浏览器。
我正在尝试使用中间件实现此目的。 到目前为止,我认为我已成功从原始服务器(http://bing.com)获取响应。我将收到的回复发送给浏览器时遇到了一些麻烦。
启动课程:
public class Startup
{
public IConfiguration Configuration { get; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment()) app.UseDeveloperExceptionPage();
app.UseProxyServer();
}
}
中间件实施:
public static class ProxyMiddlewareExtensions
{
public static IApplicationBuilder UseProxyServer(this IApplicationBuilder builder)
{
return builder.UseMiddleware<ProxyMiddleware>();
}
}
public class ProxyMiddleware
{
private readonly RequestDelegate _next;
public ProxyMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
var originalRequest = context.Request;
var absoluteUri = string.Concat(
originalRequest.Scheme,
"://",
originalRequest.Host.ToUriComponent(),
originalRequest.PathBase.ToUriComponent(),
originalRequest.Path.ToUriComponent(),
originalRequest.QueryString.ToUriComponent());
if(!absoluteUri.Contains("localhost"))
{
HttpWebRequest newRequest = WebRequest.CreateHttp(absoluteUri);
//Make a copy of the original request
CopyRequestTo(context.Request, newRequest);
//Get a response using the copied http request.
var response = (HttpWebResponse)await newRequest.GetResponseAsync();
//Modify the response going back to the browser to match the response
//received from the intended server.
CopyResponseTo(response, context);
}
await this._next(context);
}
private void CopyResponseTo(HttpWebResponse source, HttpContext destination)
{
destination.Response.OnStarting(async() =>
{
await source.GetResponseStream().CopyToAsync(destination.Response.Body);
foreach (string headerKey in source.Headers.AllKeys)
{
//============Exception Here=========
destination.Response.Headers[headerKey] = source.Headers.Get(headerKey);
}
destination.Response.StatusCode = (int)source.StatusCode;
});
}
public static void CopyRequestTo(HttpRequest source, HttpWebRequest destination)
{
destination.Method = source.Method;
foreach (var headerKey in source.Headers.Keys)
{
destination.Headers[headerKey] = source.Headers[headerKey];
}
destination.ContentType = source.ContentType;
if (source.Method != "GET" && source.Method != "HEAD" && source.ContentLength > 0)
{
var destinationStream = destination.GetRequestStream();
source.Body.CopyTo(destinationStream);
destinationStream.Close();
}
}
}
但是在更改响应时我得到了这个例外:
标题是只读的,响应已经开始
为什么即使我使用Response.OnStarting
时出现此异常?
我正在从控制台运行应用程序(不使用IIS)