1

私の node.js Web ページでは、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 スタイルのページ プレビューについて何か良いアイデアを持っている人はいますか?

4

1 に答える 1

2

writeHead基になる TCP ストリームに HTTP ヘッダーを書き込みます。 HTMLとはまったく関係ありません。

サーバーが要求された URL のホールセール HTML コンテンツを返すため、問題が発生しています。次に、この文字列を jQuery に渡します。これにより、含まれている CSS スタイルがドキュメントに追加されているようです。

一般に、ユーザーが指定した URL からランダムなコードを取得し、ページのコンテキストで実行することは、ひどい考えです。これにより、大きなセキュリティ ホールが開かれます。目にしている CSS アーティファクトはその一例です。

率直に言って、あなたのコードには多くの問題があります。

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

ここでは、サーバーが実際に何かを行う前に、ブラウザーに成功ステータス ( 200)で応答します。これは誤りです。リクエストが成功したか失敗したかがわかった後でのみ、成功コードまたはエラー コードで応答する必要があります。

        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 のsetおよびsendメソッドを使用します。次のようなもの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
    }
});
于 2013-11-05T05:04:02.137 に答える