web-dev-qa-db-ja.com

Express-ページとカスタムデータを1回のリクエストでブラウザに送信しますか?

ページをレンダリングし、カスタムデータをブラウザーに送信する方法。私が理解したように、2つのレイヤーを送信する必要があります:最初はテンプレートで、2番目はJSONデータです。このデータをバックボーンで処理したい。

チュートリアルから理解したように、expressと_bb app_は次のように対話します。

  1. _res.render_ブラウザにページを送信
  2. when _document.ready_トリガーjQuery.get to app.get('/post')
  3. app.get('/post', post.allPosts)ページにデータを送信

これは3つのステップで、1つずつ行う方法は?

_var visitCard = {
  name: 'John Smit',
  phone: '+78503569987'
};

exports.index = function(req, res, next){
  res.render('index');
  res.send({data: visitCard}); 
};
_

そして、どのようにページでこの変数をキャッチする必要がありますか__document.card_?

15
khex

renderWithDataというヘルパーメソッドをresオブジェクトに追加する独自の小さなミドルウェア関数を作成しました。

_app.use(function (req, res, next) {
    res.renderWithData = function (view, model, data) {
        res.render(view, model, function (err, viewString) {
            data.view = viewString;
            res.json(data);
        }); 
    };
    next();
});
_

ビュー名、ビューのモデル、およびブラウザーに送信するカスタムデータを受け取ります。 _res.render_を呼び出しますが、コールバック関数を渡します。これは、すぐに応答にパイプするのではなく、文字列としてコンパイル済みビューマークアップをコールバックに渡すようにExpressに指示します。ビュー文字列を取得したら、それを_data.view_としてデータオブジェクトに追加します。次に、_res.json_を使用して、コンパイルされたビューを備えたブラウザにデータオブジェクトを送信します:)

編集:

上記の1つの注意点は、リクエストをjavascriptで作成する必要があるため、ページ全体をリクエストすることはできないことです。 ajaxリクエストを行うJavaScriptを含むメインページをプルダウンするには、最初のリクエストが必要です。

これは、ユーザーがAJAXを介して新しいページに移動するときにブラウザーのURLとタイトルを変更しようとする状況に最適です。新しいページの部分ビューをページタイトルのデータとともにブラウザに送り返すことができます。次に、クライアント側のスクリプトは、ページ上の部分的なビューを配置し、ページのタイトルバーを更新し、必要に応じてURLを更新できます。

完全なHTMLドキュメントをいくつかの初期JavaScriptデータとともにブラウザーに送信する場合は、そのJavaScriptコードをビュー自体にコンパイルする必要があります。それを行うことは間違いなく可能ですが、文字列のマジックを伴わない方法を見つけたことがありません。

例えば:

_// controller.js
var someData = { message: 'hi' };
res.render('someView', { data: JSON.stringify(someData) });

// someView.jade
script.
    var someData = !{data};
_

注:jadeはデフォルトでHTMLをエスケープするため、_!{data}_の代わりに_#{data}_が使用されます。これにより、すべての引用符が_"_プレースホルダーになります。

最初は本当に奇妙に見えますが、動作します。基本的には、サーバー上のJSオブジェクトを取得し、それを文字列に変換し、その文字列をコンパイル済みビューにレンダリングしてからブラウザーに送信します。ドキュメントが最終的にブラウザに到達すると、次のようになります。

_// someSite.com/someView
<script type="text/javascript">
    var someData = { "message": "hi" };
</script>
_

うまくいけば、それは理にかなっています。この2番目のシナリオの痛みを緩和するために元のヘルパーメソッドを再作成する場合、次のようになります。

_app.use(function (req, res, next) {
    res.renderWithData = function (view, model, data) {
        model.data = JSON.stringify(data);
        res.render(view, model);
    };
    next();
});
_

これは、カスタムデータオブジェクトを取得して文字列化し、ビューのモデルに追加してから、通常どおりにビューをレンダリングするだけです。これで、res.renderWithData('someView', {}, { message: 'hi' });;を呼び出すことができます。ビューのどこかでそのデータ文字列を取得し、変数割り当てステートメントにレンダリングすることを確認する必要があります。

_html
    head
        title Some Page
        script.
            var data = !{data};
_

嘘をつくことはありませんが、このことは全体的にちょっと気分が悪くなりますが、サーバーへの余分な旅行を省くことができれば、それがその後のことです。誰かがもう少し賢いことを考えられるかもしれませんが、初めてレンダリングされる完全なHTMLドキュメントにデータが既に存在するようになる方法はわかりません。

編集2:

これが実際の例です: https://c9.io/chevex/test

プロジェクトを実行するには、(無料の)Cloud9アカウントが必要です。サインインしてapp.jsを開き、上部の緑色の実行ボタンをクリックします。

10
Chev

私のアプローチは、情報とともにCookieを送信し、クライアントからそれを使用することです。

server.js

_const visitCard = {
  name: 'John Smit',
  phone: '+78503569987'
};

router.get('/route', (req, res) => {
  res.cookie('data', JSON.stringify(pollsObj));
  res.render('index');
});
_

client.js

_const getCookie = (name) => {
  const value = "; " + document.cookie;
  const parts = value.split("; " + name + "=");
  if (parts.length === 2) return parts.pop().split(";").shift();
};

const deleteCookie = (name) => {
  document.cookie = name + '=; max-age=0;';
};

const parseObjectFromCookie = (cookie) => {
  const decodedCookie = decodeURIComponent(cookie);
  return JSON.parse(decodedCookie);
};

window.onload = () => {
  let dataCookie = getCookie('data');
  deleteCookie('data');

  if (dataCookie) {
    const data = parseObjectFromCookie(dataCookie);
    // work with data. `data` is equal to `visitCard` from the server

  } else {
    // handle data not found
  }
_


ウォークスルー

サーバーから、ページをレンダリングする前にCookieを送信するため、ページがロードされるときにCookieを使用できます。

次に、クライアントから、私が見つけた解決策と一緒にCookieを取得します here そして削除します。クッキーのコンテンツは定数に保存されます。 Cookieが存在する場合、オブジェクトとして解析し、使用します。 parseObjectFromCookie内では、最初にコンテンツをデコードし、次にJSONをオブジェクトに解析する必要があることに注意してください。

メモ

  • データを非同期で取得する場合は、Cookieを送信するように注意してくださいbefore rendering。そうしないと、res.render()が応答を終了するため、エラーが発生します。データの取得に時間がかかりすぎる場合は、その時間のレンダリングを保持しない別のソリューションを使用できます。別の方法として、クライアントからソケットを開き、サーバーに保持している情報を送信することもできます。 こちらを参照 そのアプローチについて。

  • おそらくdataは、何かを上書きする可能性があるため、Cookieに最適な名前ではありません。あなたの目的により意味のあるものを使用してください。

  • このソリューションは他のどこにも見つかりませんでした。私が知らない何らかの理由でクッキーの使用が推奨されていないかどうかはわかりません。私はちょうどそれがうまくいくと思って、それが機能したことを確認しましたが、私はこれを実稼働で使用していません。

5
Daniel Reina

使用する res.send の代わりに res.render。文字列、配列、単純な古いオブジェクトなど、あらゆる形式の生データを受け入れます。オブジェクトまたはオブジェクトの配列の場合、JSONにシリアル化します。

var visitCard = {
  name: 'John Smit',
  phone: '+78503569987'
};

exports.index = function(req, res, next){
  res.send(visitCard}; 
};
3
Brandon

この正確な目的のために作られた小さなモジュール、Steamerをチェックしてください。

https://github.com/rotundasoftware/steamer

2
Brave Dave

これを行う最もエレガントで簡単な方法は、レンダリングエンジンを使用することです(少なくとも、その関心のあるページに対して)。たとえば、ejsエンジンを使用します

node install ejs -s

Server.jsの場合:

let ejs = require('ejs');    
app.set('view engine', 'ejs');

次に、目的のindex.htmlページの名前をindex.ejsに変更し、/ viewsディレクトリに移動します。その後、(mysqlモジュールを使用して)そのページのAPI endpoitを作成できます。

app.get('/index/:id', function(req, res) { 
    db.query("SELECT * FROM products WHERE id = ?", [req.params.id], (error, results) => {
    if (error) throw error;
        res.render('index', { title: results[0] }); 
    });
});  

フロントエンドで、たとえばAxiosを使用するか、リクエストを送信しているテンプレートindex.ejsページのリンクをクリックして、GETリクエストを行う必要があります。

<a v-bind:href="'/index/' + co.id">Click</a>

ここで、co.idはVue要求とともに送信するデータパラメーター値 'co'

0
Danny