我有一段 JavaScript 代码,它使用 jQuery.post 将一些数据发送到使用 HttpListener 的 .NET 应用程序。
这是js:
$.post("http://localhost:8080/catch", { name: "John", time: "2pm" },
function(data) {
alert(data);
});
和 C#:
HttpListenerContext context = listener.GetContext();
HttpListenerRequest request = context.Request;
StreamReader reader = new StreamReader(request.InputStream);
string s2 = reader.ReadToEnd();
Console.WriteLine("Data received:" + s2);
// Obtain a response object.
HttpListenerResponse response = context.Response;
// Construct a response.
string responseString = "<HTML><BODY> Hello world!</BODY></HTML>";
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
// Get a response stream and write the response to it.
response.ContentLength64 = buffer.Length;
System.IO.Stream output = response.OutputStream;
output.Write(buffer, 0, buffer.Length);
// You must close the output stream.
output.Close();
post请求发出正常,.NET应用程序读取数据正常,但JS代码似乎没有得到响应。触发 jQuery.post 的回调函数,但 data 始终未定义。为简洁起见,我在上面省略了一些 C#,其中我为侦听器设置了前缀。
有什么想法为什么我无法在客户端取回数据吗?
编辑:我应该补充一点,当我在运行 HttpFox 的情况下运行 JS 时,我得到 Http 代码 200,'NS_ERROR_DOM_BAD_URI',我认为这与我的目标“http://localhost:8080/catch”有关,但是当我在 Firefox 中点击该资源时,我得到了很好的 HTML 响应,并且它注册为 GET, 200。
编辑:我将响应简化为“喵”,这就是 fiddler 给我的完整响应:
HTTP/1.1 200 OK
Content-Length: 4
Content-Type: text/html
Server: Microsoft-HTTPAPI/2.0
Date: Fri, 15 Apr 2011 12:58:49 GMT
meow
不要忘记通过关闭响应来释放资源。
对响应调用 Close 将强制通过底层套接字发送响应,然后释放其所有一次性对象。
在您的示例中,仅在输出流上调用 Close 方法。这将通过套接字发送响应,但不会处置与响应相关的任何资源,其中包括您引用的输出流。
// Complete async GetContext and reference required objects
HttpListenerContext Context = Listener.EndGetContext(Result);
HttpListenerRequest Request = Context.Request;
HttpListenerResponse Response = Context.Response;
// Process the incoming request here
// Complete the request and release it's resources by call the Close method
Response.Close();
我没有看到内容类型的设置。将内容类型设置为
text/html
。
response.ContentType = "text/html";
可以大大简化代码的编写。只需使用这个:
// Construct a response.
string responseString = "<HTML><BODY> Hello world!</BODY></HTML>";
context.Response.Write(responseString);
不需要
OutputStream
或大部分其他代码。如果您确实有理由使用它,请注意您实际上不应该关闭 OutputStream
。当您使用 Resopnse.OutputStream
时,您正在检索对它的引用,但您并没有取得所有权。它仍然属于 Response
对象所有,并且在请求结束时处置 Response
时将正确关闭。
致所有未来的读者
请添加响应标头。这个非常重要。现代浏览器不会完全阻止跨域请求。这意味着当您从浏览器中输入 http://localhost:13000 时,您会从 httplistener 服务器获得 html 响应,但是当您尝试从 jQuery ajax 调用 http://localhost:13000 时,您将不会获得任何响应,除非您包括下面的标题。
response.Headers.Add("Access-Control-Allow-Origin", "*");在你的 httplistener 上。
请参考
使用 HttpListener 与 Angular 的 $http.post 而不是 jQuery.Ajax
和
“Access-Control-Allow-Origin”标头如何工作?
HttpListener C#
class Program
{
static void Main(string[] args)
{
HTTPServerAsync httpServerAsync = new HTTPServerAsync();
}
}
class HTTPServerAsync
{
public HTTPServerAsync()
{
StartServer();
}
public static void StartServer()
{
HttpListener listener = new HttpListener();
const int port = 13000;
//listener.Prefixes.Add("http://112.1.1.2:" + port + "/");
listener.Prefixes.Add("http://localhost:" + port + "/");
listener.Start();
StartServerAsync(listener).ContinueWith(task => { });
}
private static void ProcessClient(HttpListenerContext context)
{
try
{
var request = context.Request;
string dataFromServer;
using (var reader = new StreamReader(request.InputStream, request.ContentEncoding))
{
dataFromServer = reader.ReadToEnd();
}
Console.WriteLine("Got command: {0}", dataFromServer);
string responseText = "<HTML><BODY><table border=\"1\"><tr><td> Hello world!</td></tr></table></BODY></HTML>"; //"Hello";
byte[] buf = Encoding.UTF8.GetBytes(responseText);
Console.WriteLine(context.Request.Url);
var response = context.Response;
response.ContentLength64 = buf.Length;
response.Headers.Add("Access-Control-Allow-Origin", "*");
response.Headers.Add("Access-Control-Allow-Methods", "POST, GET");
response.StatusCode = 200;
response.StatusDescription = "OK";
response.OutputStream.Write(buf, 0, buf.Length);
response.OutputStream.Close();
}
catch (WebException)
{
Console.WriteLine("Error reading string, closing..");
return;
}
}
private static async Task StartServerAsync(HttpListener listener)
{
while (true)
{
Console.WriteLine("Waiting for client.. ");
var context = await listener.GetContextAsync();
Console.WriteLine("Client connected!");
// ReSharper disable once CSharpWarnings::CS4014
//Task.Factory.StartNew(() => StartServerAsync(listener));
ProcessClient(context);
//await StartServerAsync(listener);
}
listener.Close();
}
}
jQuery Client AJAX call to above httplistener
<script>
$(window).on('load', function () {
$("#getDataBtn").on('click', function () {
$.ajax({
url: "http://localhost:13000",
type: "GET",
beforeSend: function () {
},
success: function (response, status) {
alert(response);
},
error: function (error, status) {
alert(error);
}
})
})
});
</script>
<button class="btn btn-primary" id="getDataBtn">Get Data</button>