获取到的request中Content-Length与实际不符的疑问
发布于 2年前 作者 hot88zh 3327 次浏览

有一个静态网页,包含一个表单,表单中有一个文件域,nodejs这边是一个简单的http服务器,在静态网页那边提交了一个文件,在nodejs这边用request.on("data",function(chunk){})获取请求正文的长度,代码如下

var _post_data = "";
request.on("data", function (chunk) {
    _post_data += chunk;
    console.log("_post_data长度:" + _post_data.length);
})

当整个获取结束之后,查看_post_data的长度与请求头中的content-length长度不符合,要少一点。。。请问这是为啥,我如何才能完整的获取到请求正文,因为想把这个请求正文,原样转发给另外一个地址(用http.request做)

看官方文档,chunk是经过解码后的字符串了,不知道是不是这个原因。。。那如何获得解码前得字符串呢,或者说不让请求正文解码,直接获取到。谢谢各位啦

28 回复

改了之后,好像大小还是不对。。。请求正文的长度又比Content-Length要长了好多,囧。。。。你知道如何把request获取到的请求体直接当做另外一个request的请求体发出去么,相当于copy了一份,如果用data监听器获取的话,是经过转码的,因为里面有文件的上传,所以请求正文会有二进制数据,不知道经过转码之后是不是就不对了。。。

@hot88zh 做简单的代理吗?如果是这样,你要挖一下坟了,很早的文章有做这方面的demo。我记得貌似是socket直接pipe,因为socket是流。。。一会找一下老资料。

另,request的编码在header里是有的,可以取到。

嗯,搞定啦~直接获取请求主体,然后再次请求,不过现在有一个非常郁闷的问题,就是用http.request请求一个地址,方法是get,其实就是一个302的Redirect,但是请求返回的结果依然是另外一个Redirect 我又把地址直接复制到浏览器里面,是可以正常返回的,状态码是200,用xmlhttprequest也是返回成功,不知道为什么http.request就不对,按道理来说不应该呀

@hot88zh 将要发送的内容转换为buffer然后再取length,就准确了

@leizongmin 嗯~已经这么搞定啦

@hot88zh 浏览器处理302一般会重新建立一个TCP连接,请求就不通过你这个代理了。 解析一下302的情况,再发个请求出去也很简单啊。转向地址Location也在header里。 不知道我理解的对不对。

@saighost 好像稍微有点出入,现在是这么一个情况,A→B→C A、B、C是三个不同的网址,其中A到B和B到C,都是程序通过location来跳转,这时候,访问C地址,应该返回200,不应该再返回302了,但是用程序的话,在访问C地址,依然返回302。。。。 我要是把C地址粘贴到浏览器里面,就直接返回200了

@hot88zh 还有如果是302,302的地址是C的说明你里面处理的时候response的header处理有问题,建议先把C改为baidu什么的,然后看什么情况。

看看你的实现和使用 node.js 进行服务器端 JavaScript 编程 这篇文章里的代理实现有什么不同?里面虽然是比较简单的入门,但是基本上应该是一样的。

@leizongmin 老雷,我的帖子是不是你干的坏事?

@saighost 今天整站被注入,不只是你的帖子,娃哈哈

看了这个文章,改为baidu之后返回的是200正常。。。。 就是下面这个地址,在浏览器访问正常,但是如果用http.request访问就不行了。。你试试。。。 http://www.google.com.hk/search?tbs=sbi:AMhZZivK0ZITunLa61jpSnTUgxTzXokI3SvM61VJdh8_1jtioUzo-LZMimgb-a3eh0eu6CtIrSOMldhyYsbBsK3H_1PaFE1c6LA4FeeeqH3ZLSO6ocA9tUmVU-XD2IsWQL91FcogEj85LxW_1D9JD62lt6jYMRYyXJAFgws_1BIuWBztJ27pNSGd-2YHGKVPQCOMubdQ9Cs86bYBsKaA1FsyM7MQDqr4WZ9sNeH_1ZLUcbDUTuWTQ25khYsCYmpX2XYDeMGtj_1xwZtlrrMDRINTYDKlCfAKy9CgqYClVWZk9xJSRNDcsyfbUk9rJIY2whiJ70B4e3J0ohq3H5wDeMPRXmM1Lh3AmMZ1sNDXuUs_1Nyey0pqYe41V-aDZzVRObYkvyakU6lUFLegybs4sQxKE8nx8OkzqqOCGqZKQGzysmkWY0XNpfMOMFGPGs-pZqU8P1kFxM1dWJSA-fpNhbxaacdZadbsb98imQVRKI-WGPlEO8y2uaFBbSvF_1L0yQciRzJpXhABB7YN8elIAnSpJRx2Xx3HKzFYqRV4bFXe-8h1ppqUblRlrjCLuH2WNPMOroFb6XEkiE0CbHFIvGnucO4nq4T3vkYUrNWC034ziV5IDfacaGqU6b4ejqSBe_1-2gz-GOdaUrtygNzYtWYlVpWl0XUXcvJuuP3hUHqs1Aqs99I5WUBclqi82YHQRytlIQo_1G16YbDiw1Z9rkJliiPX3iofsMWcWbLsXrK2FBFK4vRj1Wh_1bRlYdCO9P0Hvn6MBCtkcuQCfPKe5HcSvowpofKFlA-Dvm3E7NYVIgPpTmYeH43DyAa9-plERGVchoC_1U1IEPaBIa5qQyqKBez0232oT1A3Ijuh0FjrYYm336YwspyITrdFgFtfDrqe7jUHBC3VbdXZR1pwYm-5A3APIfbNskqiNXJ2x2F57GjFncUiTwqECyZomj4bxFPT0IbGFmzVv97LbTTdIEItAQ2ABHRNGsFG9hKy38iuSUq3DMk5_1ONm7MC4dmEypy9lun1KQ5rf18Z0RyCjs3P76StUl5MnzHBZKUJ_1gWg18c5djMvxWWURwcObDrmgaC7Mssb0CN0CRxLtW0LAzJzxpC9V4-AX3Nc_11xMt45Ui6Mmb2N0k4oIOqGYKSMcTjUK-RoiIgPw00OgNc6qBr-i6h74ArH7iD5LLSq_1f8C0aDN7Y0M0pkEnkbFtF81u7VRQs9agF8LWNv6MnlvHQEzMXNjMtcC1eTTcGiTpiUnuVtXb1hsSFnCjoO9G4D5gHfn7smJaz50Qxq3CrdQLKfpWZ8Y-BukuvbVdVR2_1vg1_1kAlU3-5owOds16WQlTsHHmIb09B8E7PwIqgJfv1y8RtiLR3zhGPxRd4TEc32pHBzdRw

用下面这段代码访问上面的地址,返回302,但是在浏览器里面直接访问上面的地址,看控制台应该直接输出200.。。。

http.get({

host:"www.google.com.hk", port:80, path:"/search?tbs=sbi:AMhZZivK0ZITunLa61jpSnTUgxTzXokI3SvM61VJdh8_1jtioUzo-LZMimgb-a3eh0eu6CtIrSOMldhyYsbBsK3H_1PaFE1c6LA4FeeeqH3ZLSO6ocA9tUmVU-XD2IsWQL91FcogEj85LxW_1D9JD62lt6jYMRYyXJAFgws_1BIuWBztJ27pNSGd-2YHGKVPQCOMubdQ9Cs86bYBsKaA1FsyM7MQDqr4WZ9sNeH_1ZLUcbDUTuWTQ25khYsCYmpX2XYDeMGtj_1xwZtlrrMDRINTYDKlCfAKy9CgqYClVWZk9xJSRNDcsyfbUk9rJIY2whiJ70B4e3J0ohq3H5wDeMPRXmM1Lh3AmMZ1sNDXuUs_1Nyey0pqYe41V-aDZzVRObYkvyakU6lUFLegybs4sQxKE8nx8OkzqqOCGqZKQGzysmkWY0XNpfMOMFGPGs-pZqU8P1kFxM1dWJSA-fpNhbxaacdZadbsb98imQVRKI-WGPlEO8y2uaFBbSvF_1L0yQciRzJpXhABB7YN8elIAnSpJRx2Xx3HKzFYqRV4bFXe-8h1ppqUblRlrjCLuH2WNPMOroFb6XEkiE0CbHFIvGnucO4nq4T3vkYUrNWC034ziV5IDfacaGqU6b4ejqSBe_1-2gz-GOdaUrtygNzYtWYlVpWl0XUXcvJuuP3hUHqs1Aqs99I5WUBclqi82YHQRytlIQo_1G16YbDiw1Z9rkJliiPX3iofsMWcWbLsXrK2FBFK4vRj1Wh_1bRlYdCO9P0Hvn6MBCtkcuQCfPKe5HcSvowpofKFlA-Dvm3E7NYVIgPpTmYeH43DyAa9-plERGVchoC_1U1IEPaBIa5qQyqKBez0232oT1A3Ijuh0FjrYYm336YwspyITrdFgFtfDrqe7jUHBC3VbdXZR1pwYm-5A3APIfbNskqiNXJ2x2F57GjFncUiTwqECyZomj4bxFPT0IbGFmzVv97LbTTdIEItAQ2ABHRNGsFG9hKy38iuSUq3DMk5_1ONm7MC4dmEypy9lun1KQ5rf18Z0RyCjs3P76StUl5MnzHBZKUJ_1gWg18c5djMvxWWURwcObDrmgaC7Mssb0CN0CRxLtW0LAzJzxpC9V4-AX3Nc_11xMt45Ui6Mmb2N0k4oIOqGYKSMcTjUK-RoiIgPw00OgNc6qBr-i6h74ArH7iD5LLSq_1f8C0aDN7Y0M0pkEnkbFtF81u7VRQs9agF8LWNv6MnlvHQEzMXNjMtcC1eTTcGiTpiUnuVtXb1hsSFnCjoO9G4D5gHfn7smJaz50Qxq3CrdQLKfpWZ8Y-BukuvbVdVR2_1vg1_1kAlU3-5owOds16WQlTsHHmIb09B8E7PwIqgJfv1y8RtiLR3zhGPxRd4TEc32pHBzdRw" },function(res){ console.log(res.statusCode); });

试试加一些headers再请求,比如 user-agent, accpet(可以照抄你浏览器的),可能是服务器端对客户端信息进行判断了呢

@leizongmin 嗯,我试试吧。这个地址获取的途径其实是用get请求地址A,获取到的302跳转,而地址A是通过另外一个地址302跳转到。。。嵌套的302跳转,所以我感觉直接用默认的headers可能就行,这个就没加。

@leizongmin 郁闷。。。。我照着浏览器里面把header都加上了,请求完了依然是302跳转,崩溃鸟,用普通的xmlrequesthttp请求都没问题,能正常返回结果。。。你试试呢,就写一个普通的http.request

看看一下代码:第一次请求返回302,然后按照给出的url再请求就200了,参考一下吧

var http = require('http');
var url = require('url');

http.get({
  host:"www.google.com.hk",
  port:80,
  path:"/search?tbs=sbi:AMhZZivK0ZITunLa61jpSnTUgxTzXokI3SvM61VJdh8_1jtioUzo-LZMimgb-a3eh0eu6CtIrSOMldhyYsbBsK3H_1PaFE1c6LA4FeeeqH3ZLSO6ocA9tUmVU-XD2IsWQL91FcogEj85LxW_1D9JD62lt6jYMRYyXJAFgws_1BIuWBztJ27pNSGd-2YHGKVPQCOMubdQ9Cs86bYBsKaA1FsyM7MQDqr4WZ9sNeH_1ZLUcbDUTuWTQ25khYsCYmpX2XYDeMGtj_1xwZtlrrMDRINTYDKlCfAKy9CgqYClVWZk9xJSRNDcsyfbUk9rJIY2whiJ70B4e3J0ohq3H5wDeMPRXmM1Lh3AmMZ1sNDXuUs_1Nyey0pqYe41V-aDZzVRObYkvyakU6lUFLegybs4sQxKE8nx8OkzqqOCGqZKQGzysmkWY0XNpfMOMFGPGs-pZqU8P1kFxM1dWJSA-fpNhbxaacdZadbsb98imQVRKI-WGPlEO8y2uaFBbSvF_1L0yQciRzJpXhABB7YN8elIAnSpJRx2Xx3HKzFYqRV4bFXe-8h1ppqUblRlrjCLuH2WNPMOroFb6XEkiE0CbHFIvGnucO4nq4T3vkYUrNWC034ziV5IDfacaGqU6b4ejqSBe_1-2gz-GOdaUrtygNzYtWYlVpWl0XUXcvJuuP3hUHqs1Aqs99I5WUBclqi82YHQRytlIQo_1G16YbDiw1Z9rkJliiPX3iofsMWcWbLsXrK2FBFK4vRj1Wh_1bRlYdCO9P0Hvn6MBCtkcuQCfPKe5HcSvowpofKFlA-Dvm3E7NYVIgPpTmYeH43DyAa9-plERGVchoC_1U1IEPaBIa5qQyqKBez0232oT1A3Ijuh0FjrYYm336YwspyITrdFgFtfDrqe7jUHBC3VbdXZR1pwYm-5A3APIfbNskqiNXJ2x2F57GjFncUiTwqECyZomj4bxFPT0IbGFmzVv97LbTTdIEItAQ2ABHRNGsFG9hKy38iuSUq3DMk5_1ONm7MC4dmEypy9lun1KQ5rf18Z0RyCjs3P76StUl5MnzHBZKUJ_1gWg18c5djMvxWWURwcObDrmgaC7Mssb0CN0CRxLtW0LAzJzxpC9V4-AX3Nc_11xMt45Ui6Mmb2N0k4oIOqGYKSMcTjUK-RoiIgPw00OgNc6qBr-i6h74ArH7iD5LLSq_1f8C0aDN7Y0M0pkEnkbFtF81u7VRQs9agF8LWNv6MnlvHQEzMXNjMtcC1eTTcGiTpiUnuVtXb1hsSFnCjoO9G4D5gHfn7smJaz50Qxq3CrdQLKfpWZ8Y-BukuvbVdVR2_1vg1_1kAlU3-5owOds16WQlTsHHmIb09B8E7PwIqgJfv1y8RtiLR3zhGPxRd4TEc32pHBzdRw"
}, function (res) {
  console.log(res.statusCode);

  var direct = url.parse(res.headers.location);
  http.get(direct, function (res) {
    console.log(res.statusCode);
  });
});

另外,服务器端还有返回cookie的,如果你在下次请求时没带上这个信息的话,某些情况下也会导致一直302的。至于为什么浏览器访问就返回200了,那是因为很多工作浏览器都帮你处理了,而你自己用Node.js来模拟这个请求时,需要熟悉http协议的工作原理才行

@leizongmin 嗯,这个确实是200,我当时的代码是让无限这样请求,直到状态码为200,也执行到这步了,但是响应的结果是错误的,跟直接用网页访问这个地址不一样。。下面的代码我也试过了,是正确的

xhr = new XMLHttpRequest();
    xhr.open("get", "http://www.google.com.hk/search?tbs=sbi:AMhZZivK0ZITunLa61jpSnTUgxTzXokI3SvM61VJdh8_1jtioUzo-LZMimgb-a3eh0eu6CtIrSOMldhyYsbBsK3H_1PaFE1c6LA4FeeeqH3ZLSO6ocA9tUmVU-XD2IsWQL91FcogEj85LxW_1D9JD62lt6jYMRYyXJAFgws_1BIuWBztJ27pNSGd-2YHGKVPQCOMubdQ9Cs86bYBsKaA1FsyM7MQDqr4WZ9sNeH_1ZLUcbDUTuWTQ25khYsCYmpX2XYDeMGtj_1xwZtlrrMDRINTYDKlCfAKy9CgqYClVWZk9xJSRNDcsyfbUk9rJIY2whiJ70B4e3J0ohq3H5wDeMPRXmM1Lh3AmMZ1sNDXuUs_1Nyey0pqYe41V-aDZzVRObYkvyakU6lUFLegybs4sQxKE8nx8OkzqqOCGqZKQGzysmkWY0XNpfMOMFGPGs-pZqU8P1kFxM1dWJSA-fpNhbxaacdZadbsb98imQVRKI-WGPlEO8y2uaFBbSvF_1L0yQciRzJpXhABB7YN8elIAnSpJRx2Xx3HKzFYqRV4bFXe-8h1ppqUblRlrjCLuH2WNPMOroFb6XEkiE0CbHFIvGnucO4nq4T3vkYUrNWC034ziV5IDfacaGqU6b4ejqSBe_1-2gz-GOdaUrtygNzYtWYlVpWl0XUXcvJuuP3hUHqs1Aqs99I5WUBclqi82YHQRytlIQo_1G16YbDiw1Z9rkJliiPX3iofsMWcWbLsXrK2FBFK4vRj1Wh_1bRlYdCO9P0Hvn6MBCtkcuQCfPKe5HcSvowpofKFlA-Dvm3E7NYVIgPpTmYeH43DyAa9-plERGVchoC_1U1IEPaBIa5qQyqKBez0232oT1A3Ijuh0FjrYYm336YwspyITrdFgFtfDrqe7jUHBC3VbdXZR1pwYm-5A3APIfbNskqiNXJ2x2F57GjFncUiTwqECyZomj4bxFPT0IbGFmzVv97LbTTdIEItAQ2ABHRNGsFG9hKy38iuSUq3DMk5_1ONm7MC4dmEypy9lun1KQ5rf18Z0RyCjs3P76StUl5MnzHBZKUJ_1gWg18c5djMvxWWURwcObDrmgaC7Mssb0CN0CRxLtW0LAzJzxpC9V4-AX3Nc_11xMt45Ui6Mmb2N0k4oIOqGYKSMcTjUK-RoiIgPw00OgNc6qBr-i6h74ArH7iD5LLSq_1f8C0aDN7Y0M0pkEnkbFtF81u7VRQs9agF8LWNv6MnlvHQEzMXNjMtcC1eTTcGiTpiUnuVtXb1hsSFnCjoO9G4D5gHfn7smJaz50Qxq3CrdQLKfpWZ8Y-BukuvbVdVR2_1vg1_1kAlU3-5owOds16WQlTsHHmIb09B8E7PwIqgJfv1y8RtiLR3zhGPxRd4TEc32pHBzdRw", true);
    xhr.onreadystatechange = function () {
        if (xhr.readyState == 4) {
            if (xhr.status == 200) {
                console.log("success!");
            }
            else if (xhr.status == 302) {
                console.log("fuck!");
            }
        }
        else {
            console.log(xhr.readyState);
        }
    }
    xhr.send(null);

@leizongmin 这就诡异了啊。。。同样的地址,用http.request请求返回的是302,用普通xmlhttprequest请求得到的是200,浏览器中直接访问也是200……

@leizongmin 找到问题了,。。。原来是google的robot.txt里面做了限制,只能通过浏览器访问,这种问题该肿么办?http.request可以做到模仿浏览器访问么?http://www.google.com/robots.txt

@hot88zh 如果是换baidu没问题,应该检查一下自己代码了,再看看header怎么处理的,是不是有什么隐藏的错误。因为直接http.request没有问题,所以跟XMLHttpRequest或或浏览器访问没关系。

@hot88zh 参考我的第二条回复,cookie 理论上是可以完全模拟出浏览器那样的请求的

@leizongmin 多谢!弄好了……果然是模拟一下cookie就可以了

搞定啦,多谢~

请问http.get方法模拟访问一个页面,需要带2个cookie,该如何写啊?

回到顶部