res.writehead真的写到我的html页面的头部吗?

时间:2013-11-04 22:49:40

标签: javascript jquery html node.js

在我的node.js网页中,我正在进行类似于Facebook链接预览的页面预览。我正在打电话来获取页面的html,并使用它来创建预览。

$.ajax({
    type: 'GET',
    data: { "html": url },
    url: "/htmlTest",
    success: function (data) {
            imgArray = [];
            $('img', data).each(function () {
                imgArray.push(this.src);
            });
  ...

这是处理请求的服务器端代码。

app.get('/htmlTest', function (req, res) {
    res.writeHead(200, { 'content-type': 'text/html' });
        request(req.query.html, function (error, response, body) {
            if (error) {
                res.write(error.toString());
                res.end('\n');
            }
            else if (response.statusCode == 200) {
                res.write(body);
                res.end('\n');
            }
        })
});

现在我注意到的是,它只会将其他页面使用的任何css插入到我的页面中,这可以真正搞砸了所有内容。为什么会这样?

另外,虽然我很喜欢,但有没有人对facebook风格的页面预览有更好的想法?

1 个答案:

答案 0 :(得分:1)

没有。 writeHead将HTTP标头写入底层TCP流。它与HTML完全无关。

您遇到了问题,因为您的服务器会返回所请求网址的批发HTML内容。然后将此字符串传递给jQuery,这显然将包含的CSS样式添加到您的文档中。

通常,从用户提供的URL中获取随机代码并在页面上下文中运行是一个糟糕的主意。它打开了你的安全漏洞 - 你看到的CSS工件就是一个例子。

说实话,你的代码有很多问题,所以当我指出一些问题时请耐心等待。

app.get('/htmlTest', function (req, res) {
    res.writeHead(200, { 'content-type': 'text/html' });

在这里,您回复浏览器的成功状态(200 beore 您的服务器实际上做了什么。这是不正确的:在您知道请求是成功还是失败后,您应该只响应成功或错误代码。

        request(req.query.html, function (error, response, body) {
            if (error) {
                res.write(error.toString());
                res.end('\n');
            }

这是一个回复错误代码的好地方,因为我们知道请求确实失败了。 res.send(500, error)可以解决问题。

            else if (response.statusCode == 200) {
                res.write(body);
                res.end('\n');
            }

这是我们可以用成功代码回复的地方。而不是使用writeHead,使用Express的setsend方法 - Content-Length之类的内容将被正确设置:

res.set('Content-Type', 'text/html');
res.send(body);

现在如果response.statusCode != 200会发生什么?你没有处理这种情况。 error仅在网络错误(例如无法连接到目标服务器)的情况下设置。目标服务器仍然可以以非200状态响应,并且您的节点服务器永远不会响应浏览器。事实上,连接将挂起,直到用户杀死它。这可以通过简单的else res.end()修复。


即使解决了这些问题,我们仍然没有解决这样一个事实,即尝试解析浏览器中的任意HTML并不是一个好主意。

如果我是你,我会使用一些解析HTML到服务器上的DOM的东西,然后我只将必要的信息作为JSON返回给浏览器。 cheerio是您可能想要使用的模块 - 它看起来就像jQuery,只在服务器上运行。

我会这样做:

var cheerio = require('cheerio'), url = require('url'), request = require('request');

app.get('/htmlTest', function(req, res) {
    request(req.query.url, function(err, response, body) {
        if (err) res.send(500, err); // network error, send a 500
        else if (response.status != 200) res.send(500, { httpStatus: response.status }); // server returned a non-200, send a 500
        else {
            // WARNING!  We should probably check that the response content-type is html
            var $ = cheerio.load(body); // load the returned HTML into cheerio
            var images = [];
            $('img').each(function() {
                // Image srcs can be relative.
                // You probably need the absolute URL of the image, so we should resolve the src.
                images.push(url.resolve(req.query.url, this.src));
            });

            res.send({ title: $('title').text(), images: images }); // send back JSON with the image URLs
        }
    });
});

然后从浏览器:

$.ajax({
    url: '/htmlTest',
    data: { url: url },
    dataType: 'json',
    success: function(data) {
        // data.images has your image URLs
    },
    error: function() {
        // something went wrong
    }
});