Làm cách nào để chuyển biến từ tệp mẫu ngọc sang tệp kịch bản?


119

Tôi đang gặp sự cố với một biến (cấu hình) được khai báo trong tệp mẫu ngọc bích (index.jade) không được chuyển đến tệp javascript, điều này sau đó khiến javascript của tôi gặp sự cố. Đây là tệp (views / index.jade):

h1 #{title}

script(src='./socket.io/socket.io.js')
script(type='text/javascript')
  var config = {};
  config.address = '#{address}';
  config.port = '#{port}';
script(src='./javascripts/app.js')

Đây là một phần trong app.js của tôi (phía máy chủ):

  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(__dirname + '/public'));
});

app.configure('development', function(){
  app.set('address', 'localhost');
  app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.configure('production', function(){
  app.use(express.errorHandler());
});

// Routes

app.get('/', function(req, res){
  res.render('index', {
    address: app.settings.address,
    port: app.settings.port
});
});

if (!module.parent) {
  app.listen(app.settings.port);
  console.log("Server listening on port %d",
app.settings.port);
}

// Start my Socket.io app and pass in the socket
require('./socketapp').start(io.listen(app));

Và đây là một phần của tệp javascript của tôi bị lỗi (public / javascripts / app.js):

(function() {
        var socket = new io.Socket(config.address, {port: config.port, rememberTransport: false});

Tôi đang chạy trang web ở chế độ phát triển (NODE_ENV = phát triển) trên localhost (máy của riêng tôi). Tôi đang sử dụng trình kiểm tra nút để gỡ lỗi, điều này cho tôi biết rằng biến cấu hình không được xác định trong public / javascripts / app.js.

Có ý kiến ​​gì không ?? Cảm ơn!!


Câu trả lời:


174

hơi muộn nhưng ...

script.
  loginName="#{login}";

Điều này đang hoạt động tốt trong kịch bản của tôi. Trong Express, tôi đang làm điều này:

exports.index = function(req, res){
  res.render( 'index',  { layout:false, login: req.session.login } );
};

Tôi đoán viên ngọc bích mới nhất có gì khác?

Merc.

chỉnh sửa: đã thêm "." sau kịch bản để ngăn cảnh báo Ngọc.


1
Cảm ơn vì đã chấp nhận câu trả lời! Vì vậy, vấn đề thực sự với mã của bạn là gì?
Merc

Có, tôi cũng làm cho điều này hoạt động bằng cách đặt biến cục bộ trong mẫu trong dấu ngoặc kép và chỉ báo # {}.
Askdesigners

Câu trả lời này rất nguy hiểm, câu trả lời của lagginreflex mã hóa chính xác chuỗi (các dòng mới trong tên đăng nhập có thể cho phép thực thi mã).
Paul Grove

Vì vậy, vấn đề chỉ là dấu ngoặc kép đơn trong khi dự kiến ​​sẽ có dấu ngoặc kép, phải không?
Augustin Riedinger,

Đối với tôi, vấn đề là dấu chấm. Tôi đã có nó ở cuối khối kịch bản. Với dấu chấm sau từ khóa "script" nó hoạt động như một sự quyến rũ. Cảm ơn bạn!
Mirko

102

!{}là để nội suy mã không thoát , phù hợp hơn cho các đối tượng

script var data = !{JSON.stringify(data).replace(/<\//g, '<\\/')}

{ foo: 'bar' }
// becomes:
<script>var data = {"foo":"bar"}</script>

{ foo: 'bar</script><script>alert("xss")//' }
// becomes:
<script>var data = {"foo":"bar<\/script><script>alert(\"xss\")//"}</script>

Ý tưởng là ngăn chặn kẻ tấn công:

  1. Thoát khỏi biến: JSON.stringifythoát khỏi dấu ngoặc kép
  2. Thoát khỏi thẻ script: nếu nội dung biến (mà bạn có thể không kiểm soát được nếu đến từ cơ sở dữ liệu cho ví dụ:) có một </script>chuỗi, câu lệnh thay thế sẽ xử lý nó

https://github.com/pugjs/pug/blob/355d3dae/examples/dynamicscript.pug


#{}là cho phép nội suy chuỗi thoát , chỉ phù hợp nếu bạn đang làm việc với chuỗi. Nó không hoạt động với các đối tượng

script var data = #{JSON.stringify(data)}

//=> <script>var data = {&quot;foo&quot;:&quot;bar&quot;}</script>

1
Câu trả lời xuất sắc! Tôi đã tìm kiếm chủ đề này trong hơn 20 phút và không có câu trả lời nào khác cho biết sự khác biệt giữa! {} Và # {}. Cả thời gian này, tôi chỉ nghĩ! {] Là từ tương đương với # {} ... Cảm ơn bạn một lần nữa.
Patrick E.

Về đầu trang! Câu trả lời chính xác.
Scarysize

Câu trả lời tuyệt vời, và nó hoạt động cho các đối tượng! Btw, là JSONmột đối tượng toàn cục? Nó dường như hoạt động mà không cần nhập bất kỳ thư viện nào khác. Nếu vậy, hỗ trợ trình duyệt thì sao?
chharvey

@chharvey JSON là một nội dung ngôn ngữ javascript (như Date hoặc Math), tất cả các trình duyệt đều hỗ trợ nó.
laggingreflex 23/02/16

1
Đồng ý rằng đây là câu trả lời tốt nhất, nhưng tôi không nghĩ rằng đây là nơi thích hợp để thoát khỏi những chuỗi nguy hiểm tiềm ẩn. IMO sẽ tốt hơn nếu bỏ qua lệnh replacegọi trong mã này và coi giá trị này giống như bất kỳ đầu vào nào khác. JSON.stringify được đảm bảo tạo ra javascript hợp lệ (hoặc không thành công) và sau khi bạn có giá trị tiềm ẩn nguy hiểm này trong bộ nhớ, bạn có thể đảm bảo làm sạch nó nếu cần trước khi sử dụng.
Riley Lark

9

Trong trường hợp của tôi, tôi đang cố gắng chuyển một đối tượng vào một khuôn mẫu thông qua một tuyến đường nhanh (giống như thiết lập OP). Sau đó, tôi muốn chuyển đối tượng đó vào một hàm mà tôi đang gọi thông qua thẻ script trong mẫu pug. Mặc dù câu trả lời của lagginreflex khiến tôi kết thúc, nhưng tôi đã kết thúc với những điều sau:

script.
    var data = JSON.parse('!{JSON.stringify(routeObj)}');
    funcName(data)

Điều này đảm bảo đối tượng đã được chuyển vào như mong đợi, thay vì cần phải giải thích trong hàm. Ngoài ra, các câu trả lời khác dường như hoạt động tốt với nguyên thủy, nhưng khi mảng, v.v. được chuyển cùng với đối tượng, chúng được phân tích cú pháp thành giá trị chuỗi.


7

Nếu bạn giống tôi và bạn sử dụng phương pháp truyền biến này rất nhiều, thì đây là một giải pháp không cần ghi mã.

Trong tuyến node.js của bạn, hãy chuyển các biến trong một đối tượng được gọi window, như sau:

router.get('/', function (req, res, next) {
    res.render('index', {
        window: {
            instance: instance
        }
    });
});

Sau đó, trong tệp bố cục pug / jade của bạn (ngay trước tệp block content), bạn lấy chúng ra như sau:

if window
    each object, key in window
        script.
            window.!{key} = !{JSON.stringify(object)};

Khi tệp layout.pug của tôi được tải với mỗi tệp pug, tôi không cần phải 'nhập' nhiều lần các biến của mình.

Bằng cách này, tất cả các biến / đối tượng được chuyển đến window'ma thuật' sẽ kết thúc trong windowđối tượng thực của trình duyệt của bạn, nơi bạn có thể sử dụng chúng trong Reactjs, Angular, ... hoặc vanilla javascript.


1
Đây là câu trả lời tốt nhất mà tôi đã thấy.
Tohir

3

Đây là cách tôi giải quyết vấn đề này (sử dụng dẫn xuất MEAN)

Các biến của tôi:

{
  NODE_ENV : development,
  ...
  ui_varables {
     var1: one,
     var2: two
  }
}

Đầu tiên, tôi phải đảm bảo rằng các biến cấu hình cần thiết đã được chuyển. MEAN sử dụng gói nconf nút và theo mặc định được thiết lập để giới hạn các biến được chuyển từ môi trường. Tôi đã phải khắc phục điều đó:

config / config.js:

nguyên:

nconf.argv()
  .env(['PORT', 'NODE_ENV', 'FORCE_DB_SYNC'] ) // Load only these environment variables
  .defaults({
  store: {
    NODE_ENV: 'development'
  }
});

sau khi sửa đổi:

nconf.argv()
  .env('__') // Load ALL environment variables
  // double-underscore replaces : as a way to denote hierarchy
  .defaults({
  store: {
    NODE_ENV: 'development'
  }
});

Bây giờ tôi có thể đặt các biến của mình như sau:

export ui_varables__var1=first-value
export ui_varables__var2=second-value

Lưu ý: Tôi đã đặt lại "chỉ báo thứ bậc" thành "__" (dấu gạch dưới kép) vì mặc định của nó là ":", điều này làm cho các biến khó đặt hơn từ bash. Xem một bài viết khác trên chủ đề này.

Bây giờ là phần ngọc: Tiếp theo, các giá trị cần được hiển thị, để javascript có thể nhận chúng ở phía máy khách. Một cách đơn giản để ghi các giá trị này vào tệp chỉ mục. Vì đây là ứng dụng một trang (góc cạnh) nên trang này luôn được tải đầu tiên. Tôi nghĩ lý tưởng nhất đây là một tệp bao gồm javascript (chỉ để giữ mọi thứ sạch sẽ), nhưng điều này tốt cho một bản demo.

app / controllers / index.js:

'use strict';
var config = require('../../config/config');

exports.render = function(req, res) {
  res.render('index', {
    user: req.user ? JSON.stringify(req.user) : "null",
    //new lines follow:
    config_defaults : {
       ui_defaults: JSON.stringify(config.configwriter_ui).replace(/<\//g, '<\\/')  //NOTE: the replace is xss prevention
    }
  });
};

app / views / index.jade:

extends layouts/default

block content
  section(ui-view)
    script(type="text/javascript").
    window.user = !{user};
    //new line here
    defaults = !{config_defaults.ui_defaults};

Trong html được kết xuất của tôi, điều này mang lại cho tôi một tập lệnh nhỏ hay:

<script type="text/javascript">
 window.user = null;         
 defaults = {"var1":"first-value","var2:"second-value"};
</script>        

Từ thời điểm này, thật dễ dàng cho góc sử dụng mã.


Đây là một cách rất dài để nói những gì câu trả lời được chấp nhận đã nói. Hơn nữa, đề cập đến MEAN, nconf, v.v. đều không liên quan. Câu hỏi là về cách chuyển các biến cho máy khách, không phải về cách bạn đã thực hiện ngăn xếp nhà phát triển của mình. Tuy nhiên, không phản đối, vì bạn vẫn nỗ lực rất nhiều trong câu trả lời này.
Mrchief

quá phức tạp
andygoestohollywood

2

Xem câu hỏi này: JADE + EXPRESS: Lặp lại đối tượng trong mã JS nội tuyến (phía máy khách)?

Im có cùng một vấn đề. Jade không chuyển các biến cục bộ trong (hoặc thực hiện bất kỳ tạo mẫu nào) cho các tập lệnh javascript, nó chỉ chuyển toàn bộ khối dưới dạng văn bản theo nghĩa đen. Nếu bạn sử dụng các biến cục bộ 'address' và 'port' trong tệp Jade của mình phía trên thẻ script, chúng sẽ hiển thị.

Các giải pháp khả thi được liệt kê trong câu hỏi mà tôi đã liên kết ở trên, nhưng bạn có thể: - chuyển mọi dòng vào dưới dạng văn bản không thoát (! = Ở đầu mỗi dòng) và chỉ cần đặt "-" trước mỗi dòng javascript sử dụng biến cục bộ, hoặc: - Chuyển các biến vào thông qua một phần tử dom và truy cập thông qua JQuery (xấu xí)

Không có cách nào tốt hơn? Có vẻ như những người tạo ra Jade không muốn hỗ trợ javascript đa dòng, như được hiển thị bởi chuỗi này trong GitHub: https://github.com/visionmedia/jade/pull/405

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.