【发布时间】:2011-12-30 06:30:23
【问题描述】:
我用 TcpListener 创建了服务器,它以虚拟 HTTP 响应每个请求。在客户端,我使用 jQuery Ajax 向该服务器发出请求。服务器获取成功请求并响应。
问题是如果我通过输入地址向浏览器发出请求,它可以工作并且我可以看到结果。如果我尝试发出 jQuery.ajax(...) 请求,那么 ajax 会失败并出现错误。如果我使用 Chrome 检查器来监控网络,我发现它甚至没有得到服务器的响应。为什么会这样?
我的任务远比我将与您分享的代码大得多。但它的行为是一样的。
.NET C#@服务器端:
using System;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;
namespace Server {
public class Server
{
public static void Main()
{
try
{
TcpListener tcpListener = new TcpListener(IPAddress.Any, 1234);
tcpListener.Start();
while (true)
{
Socket socket = tcpListener.AcceptSocket();
DummyServer server = new DummyServer(socket);
Thread thrd = new Thread(new ThreadStart(server.Run));
thrd.Start();
}
}
catch (Exception e)
{
Console.WriteLine("Error..... " + e.StackTrace);
}
}
}
public class DummyServer
{
public DummyServer(Socket socket)
{
_socket = socket;
}
Socket _socket;
public void Run()
{
try
{
// Get stream
var networkStream = new NetworkStream(_socket);
// Read from stream and decode to string
byte[] reqBuffer = new byte[32768];
int read = networkStream.Read(reqBuffer, 0, reqBuffer.Length);
string requestString = Encoding.UTF8.GetString(reqBuffer , 0, read);
Console.WriteLine(requestString);
Console.WriteLine();
// Dummy response HTTP
String responseString =
"HTTP/1.1 200 OK\r\n" +
"Content-Type: application/json\r\n" +
"Content-Length: 15\r\n" +
"\r\n" +
"{\"test\":\"test\"}";
Console.WriteLine(responseString);
Console.WriteLine();
// Write response
byte[] respBuffer = Encoding.UTF8.GetBytes(responseString);
networkStream.Write(respBuffer, 0, respBuffer.Length);
networkStream.Close();
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace);
Console.WriteLine(e.Message);
}
finally
{
// Disconnect and close the socket.
if (_socket != null)
{
if (_socket.Connected)
{
_socket.Close();
}
}
}
}
}
}
HTML 和 jQuery Ajax @ 客户端:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
jQuery.ajax({
url: 'http://localhost:1234',
type: 'POST',
data: JSON.stringify({test: "test"}),
dataType: 'text',
success: function(result) {
$("body").append("nice<br />");
},
error: function(a, b, c) {
$("body").append("damn<br />");
}
});
$("body").append("done<br />");
});
</script>
</head>
<body>
</body>
</html>
我做错了什么?浏览器可以理解这个响应,因为它可以从各种 s*it 中解析 html?
编辑#1
我调试了 DummyServer 并且 ajax 在我开始写入流时出错。即使我将超时参数设置为 ajax 请求并逐步调试它,它也会在同一步骤中给我错误(希望流式传输)。
编辑#2
当我分别编写 HTTP 标头和数据时,数据末尾的 2 个字节在传输后会丢失。
如果我一次编写整个 Dummy HTTP,那么它们就不会迷路。似乎 NetworkStream.Write 方法在我提供给它的数据之后写入了额外的 \r\n。
// Dummy response HTTP Headers
String responseHeader =
"HTTP/1.1 200 OK\r\n" +
"Content-Type: application/json\r\n" +
"Content-Length: 8\r\n" +
"\r\n"
// Dummy response data
String responseData =
"12345678";
//Write header
byte[] respBuffer = Encoding.UTF8.GetBytes(responseHeader );
networkStream.Write(respBuffer, 0, respBuffer.Length);
//Write data
respBuffer = Encoding.UTF8.GetBytes(responseData );
networkStream.Write(respBuffer, 0, respBuffer.Length);
networkStream.Close();
浏览器将显示 123456
// Dummy response HTTP
String responseString =
"HTTP/1.1 200 OK\r\n" +
"Content-Type: application/json\r\n" +
"Content-Length: 8\r\n" +
"\r\n" +
"12345678";
//Write Dummy HTTP
byte[] respBuffer = Encoding.UTF8.GetBytes(responseHeader );
networkStream.Write(respBuffer, 0, respBuffer.Length);
networkStream.Close();
浏览器将显示 12345678
如果 NetworkStream.Write 方法在我写入的字节之后写入额外的 \r\n ,那么这不是问题吗?
解决方案
您可以将 jsonp 与 GET 一起使用。 jQuery.getJSON(url, 回调);
如果你需要 POST,那么使用 Proxy,如下所示。
如您所见,不同端口和域之间存在策略问题。解决它的最佳方法是将某种代理放入您的域和端口。我是用 php 做的。
我的通信是使用 JSON 完成的。在两端都有我自己定义的结构。所以我只是将我的请求转发给主机并返回给客户端。我只需要为 ajax 设置足够大的超时时间。
<?php
function post_request($data, $referer='') {
$host = "localhost";
$port = 7777;
$fp = fsockopen($host, $port, $errno, $errstr, 5);
if ($fp){
// send the request headers:
fputs($fp, "POST / HTTP/1.1\r\n");
fputs($fp, "Host: $host\r\n");
if ($referer != '')
fputs($fp, "Referer: $referer\r\n");
fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
fputs($fp, "Content-length: ". strlen($data) ."\r\n");
fputs($fp, "Connection: close\r\n\r\n");
fputs($fp, $data);
$result = '';
while(!feof($fp)) {
// receive the results of the request
$result .= fgets($fp, 128);
}
}
else {
return array(
'status' => 'err',
'error' => "$errstr ($errno)"
);
}
// close the socket connection:
fclose($fp);
// split the result header from the content
$result = explode("\r\n\r\n", $result, 2);
$header = isset($result[0]) ? $result[0] : '';
$content = isset($result[1]) ? $result[1] : '';
// return as structured array:
return array(
'status' => 'ok',
'header' => $header,
'content' => $content
);
}
$req = post_request($_POST['data']); // on jQuery ajax side data must be "data: 'data='+JSON.stringify({test: "test"}),
header("Content-Type: application/json");
echo $req['content'];
?>
【问题讨论】:
-
我开始使用 FireFox 和 FireBug 进行调试。也看到错误:imm.io/bEQA 就像您在 FireFox 中看到的那样,它确实获得了标题...但是数据在哪里?
-
一目了然,您在代码示例中尝试访问的端口号与您在屏幕截图中使用的端口号不同。在屏幕截图中,您访问的是localhost:7777,而不是localhost:1234
-
对不起。我用于服务器和客户端的端口号是 7777 而不是 1234。问题仍然存在......
标签: c# ajax httprequest httpresponse tcplistener