HttpListener响应在侦听器停止之前没有发送



我使用下面的代码来使用浏览器登录获取oAuth代码,它工作得很好。返回验证码,但是responseOutput.WriteAsync()和http.stop()之间有一些时间问题。

在调试时(下面****上的断点),然后响应按预期返回给浏览器。

如果我注释掉http.stop()行(下面的****),那么响应将按预期返回给浏览器。

但是如果我像往常一样运行代码,那么浏览器显示"无法找到页面",所以,它看起来好像responseOutput.WriteAsync()实际上没有完成(不是开始'等待')。我还需要做什么来确保在停止侦听器之前完全发送响应吗?

await GetAuthorizationCode();
public async Task GetAuthorizationCode() {

// Creates an Listener
string redirectUri = "http://127.0.0.1:12345"; 
HttpListener http = new HttpListener();
http.Prefixes.Add(redirectUri);
http.Start();
// Open auth page in browser
string authUri = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?........"; 
var authorizationRequest = authUri;
Process.Start(authorizationRequest);
// Wait for auth response.
HttpListenerContext context = await http.GetContextAsync();
var sCode = context.Request.QueryString.Get("code");
//Send response to the browser.
HttpListenerResponse response = context.Response;
string responseString = string.Format("<html><head></head><body>Auth OK.</body></html>");
var buffer = Encoding.UTF8.GetBytes(responseString);
response.ContentLength64 = buffer.Length;
using (Stream responseOutput = response.OutputStream)
{
await responseOutput.WriteAsync(buffer, 0, buffer.Length);
responseOutput.Close();
}
//****** this line causes problems
http.Stop();
AuthorizationCode = sCode;
}

似乎我必须在http.stop()之前设置KeepAlive

response.KeepAlive = False

即使有呼叫响应。关闭和/或在响应周围使用'using'块,它仍然需要此设置。

从一个旧的http处理程序我做了一段时间,我有这个代码:

protected static void WriteString(HttpListenerResponse response, HttpContentType contentType, Encoding encoding, string content)
{
byte[] outputBuffer = encoding.GetBytes(content);
response.ContentType = contentType.Value + "; charset=" + encoding.BodyName;
response.ContentLength64 = outputBuffer.Length;
response.Close(outputBuffer, true);
}

这段代码一直活跃在一个程序上,通常每天服务几千个请求,如果不是几周的话,也会持续几天,从来没有出现过任何关于内存泄漏的问题。

从文档:

您可以通过设置各种属性来定制响应,例如StatusCode、StatusDescription和Cookies。使用HttpListenerResponse。OutputStream属性以获取流实例可以将响应数据写入其中。最后,发送响应数据

https://learn.microsoft.com/en us/dotnet/api/system.net.httplistenerresponse?view=net - 6.0

与我的想法相反,HttpListener文档声明关闭输出流:

https://learn.microsoft.com/en us/dotnet/api/system.net.httplistener?view=net - 6.0

这很令人困惑:

System.IO.Stream output = response.OutputStream;
output.Write(buffer,0,buffer.Length);
// You must close the output stream.
output.Close();
listener.Stop();

我建议尝试下面的代码:

using (Stream responseOutput = response.OutputStream)
{
await responseOutput.WriteAsync(buffer, 0, buffer.Length);

//The following two lines are possibly unnecesary in an unsing statement
//responseOutput.Flush(); //Ensure content placed on the right place
//responseOutput.Close(); 
}
response.Close();
http.Stop();

—Update—

我可以在。net 6.0下运行以下代码,没有任何问题,并在浏览器上得到响应内容:

class Program
{
static async Task Main(string[] args)
{
await RunUntilServeOneRequest();
}
private static async Task RunUntilServeOneRequest()
{
Console.WriteLine("Starting...");
// Creates an Listener
string listenUri = "http://127.0.0.1:12346/";
HttpListener http = new HttpListener();
http.Prefixes.Add(listenUri);
http.Start();
// Wait for request.
Console.WriteLine("Awaiting request to " + listenUri);
HttpListenerContext context = await http.GetContextAsync();
//Send response to the browser.
HttpListenerResponse response = context.Response;
string responseString = string.Format($"<html><head></head><body>Hello world: {DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")}</body></html>");
byte[] buffer = Encoding.UTF8.GetBytes(responseString);
response.ContentLength64 = buffer.Length;
using (Stream responseOutput = response.OutputStream)
{
await responseOutput.WriteAsync(buffer, 0, buffer.Length);
responseOutput.Close();
}
response.Close();
Console.WriteLine("Request answered");
http.Stop();
}
}

最新更新