Kết xuất chế độ xem HTML cơ bản?


279

Tôi có một ứng dụng node.js cơ bản mà tôi đang cố gắng sử dụng Express framework. Tôi có một viewsthư mục nơi tôi có một index.htmltập tin. Nhưng tôi nhận được lỗi sau khi tải trình duyệt web.

Lỗi: Không thể tìm thấy mô-đun 'html'

Dưới đây là mã của tôi.

var express = require('express');
var app = express.createServer();

app.use(express.staticProvider(__dirname + '/public'));

app.get('/', function(req, res) {
    res.render('index.html');
});

app.listen(8080, '127.0.0.1')

Tôi đang thiếu gì ở đây?

Câu trả lời:


298

Bạn có thể có ngọc bao gồm một trang HTML đơn giản:

trong lượt xem / index.jade

include plain.html

trong lượt xem / plain.html

<!DOCTYPE html>
...

và app.js vẫn có thể kết xuất ngọc:

res.render(index)

1
Chỉ cần lưu ý rằng những gì tôi muốn là chỉ phục vụ một tệp .html vì ứng dụng của tôi là một trang duy nhất;)
diosney

1
Chúng tôi có thể bao gồm nhiều trang HTML / JS với phương pháp này không?
dùng3398326

6
bạn có thể kết xuất trang html đó mà không có mẫu ngọc chỉ để thử nghiệm ban đầu không?
Tích cực,

1
Vậy chúng ta có phải tạo một mẫu ngọc cho mỗi tệp HTML không?
Chris - Jr

4
Nhiều hơn một hack hơn là một giải pháp.
Ozil

226

Nhiều câu trả lời đã hết hạn.

Sử dụng express 3.0.0 và 3.1.0, các công việc sau:

app.set('views', __dirname + '/views');
app.engine('html', require('ejs').renderFile);

Xem các bình luận bên dưới để biết cú pháp thay thế và hãy cẩn thận để thể hiện 3,4+:

app.set('view engine', 'ejs');

Sau đó, bạn có thể làm một cái gì đó như:

app.get('/about', function (req, res)
{
    res.render('about.html');
});

Điều này giả định rằng bạn có quan điểm của mình trong viewsthư mục con và rằng bạn đã cài đặt ejsmô-đun nút. Nếu không, hãy chạy như sau trên bảng điều khiển Node:

npm install ejs --save

@MichaelDausmann, chúc mừng, tôi đã đưa thông tin đó vào câu trả lời.
Drew Noakes

tại sao res.render yêu cầu phần mở rộng .html trong trường hợp này nhưng không phải trong trường hợp mặc định với ngọc. với mã soạn sẵn, nó chỉ gọi res.render ('index', {title: 'Express'}); nhưng ở đây, đó là: res.render ('about.html');
Siêu việt

6
Với Express 3.4.2: app.set ('công cụ xem', 'ejs');
roland

3
Bạn nên sử dụng lệnh 'npm install ejs --save' để cập nhật gói.json của bạn
Tom Teman

8
tại sao bạn cần ejs?
Tích cực,

71

Từ Hướng dẫn Express.js: Xem kết xuất

Xem tên tệp có dạng Express.ENGINE, ENGINEtên của mô-đun sẽ được yêu cầu. Ví dụ, chế độ xem layout.ejssẽ báo cho hệ thống xemrequire('ejs') , mô-đun đang được tải phải xuất phương thứcexports.render(str, options) để tuân thủ Express, tuy nhiên app.register()có thể được sử dụng để ánh xạ các công cụ sang phần mở rộng tệp, ví dụ như foo.htmlcó thể được hiển thị bằng ngọc.

Vì vậy, hoặc bạn tạo trình kết xuất đơn giản của riêng bạn hoặc bạn chỉ cần sử dụng ngọc bích:

 app.register('.html', require('jade'));

Thêm về app.register.

Lưu ý rằng trong Express 3, phương thức này được đổi tên app.engine


57
Lưu ý- app.register đã được đổi tên thành app.engine trong Express 3.
Spongeboy

8
Xem câu trả lời từ Andrew Homeyer. Đó là câu trả lời thực tế.
David Betz

7
Từ một số câu trả lời khác, cho Express 4 tôi đã kết thúc bằng cách sử dụngapp.engine('.html', require('ejs').renderFile);
CrazyPyro

Trong express 4, bạn cũng có thể sử dụng: app.set ('view engine', 'jade');
Daniel Huang

48

Bạn cũng có thể đọc tệp HTML và gửi nó:

app.get('/', (req, res) => {
    fs.readFile(__dirname + '/public/index.html', 'utf8', (err, text) => {
        res.send(text);
    });
});

23
giải pháp này là xấu vì không có bộ nhớ đệm của các tập tin; nó được đọc cho mọi yêu cầu.
Marcel Falliere

2
nó có khả năng khá dễ dàng để lưu trữ nó bằng tay. Chỉ lưu trữ tệp đã đọc một biến và chỉ đọc lại, nếu biến đó trống. Bạn cũng có thể sử dụng một đối tượng JS và lưu trữ các tệp khác nhau trong các biến khác nhau, với dấu thời gian. Chắc chắn rằng nó hoạt động nhiều hơn hầu hết mọi người sẽ làm, nhưng nó tốt với những người mới sử dụng nút. Thật dễ hiểu
Naman Goel

5
Rất tiếc. Điều này đánh bại toàn bộ điểm của các kiến ​​trúc được định hướng theo quy ước (như MVC).
David Betz

@MarcelFalliere Bạn cho rằng anh ta muốn lưu trữ tệp hoặc anh ta không muốn sử dụng giải pháp bộ đệm tùy chỉnh. Cảm ơn bạn keegan3d cho câu trả lời.
Benny

@MarcelFalliere Sau đó, giải pháp nào là đúng? Tôi thấy các câu trả lời khác trưng bày các phụ thuộc mới. Có cần thiết chỉ để phục vụ các tệp html?
JCarlosR

45

thử cái này. nó làm việc cho tôi

app.configure(function(){

  .....

  // disable layout
  app.set("view options", {layout: false});

  // make a custom html template
  app.register('.html', {
    compile: function(str, options){
      return function(locals){
        return str;
      };
    }
  });
});

....

app.get('/', function(req, res){
  res.render("index.html");
});

2
đã gặp sự cố với cấu hình chính xác ở trên, vì vậy tôi đã xóa dấu chấm khỏi ".html" và thêm vào đây: app.set ('view engine', 'html'); app.set ('lượt xem', __dirname + '/ lượt xem'); cho một kết xuất hoàn hảo
bijou Trouvaille

8
Điều này hơi lạ ... bạn nên phục vụ html dưới dạng tệp tĩnh. Điều này cũng cung cấp cho bạn lợi ích của bộ nhớ đệm tốt hơn. Tạo một "trình biên dịch html" tùy chỉnh có vẻ sai. Nếu bạn cần gửi một tệp từ trong một tuyến đường (điều mà bạn rất hiếm khi cần làm) chỉ cần đọc và gửi nó. Nếu không, chỉ cần chuyển hướng đến html tĩnh.
enyo

2
@Enyo bình luận này có vẻ kỳ quặc, xem xét CÁCH LÀM những gì bạn đang nói nên được thực hiện là CÂU HỎI ĐƯỢC HỎI, và câu trả lời của bạn là chỉ cần làm điều đó. Làm thế nào để bạn phục vụ một html tĩnh với bộ nhớ đệm?
Kyeotic

3
Tôi thấy một lỗi trên app.register. Có lẽ nó đã bị phản đối trong express 3.0.0.rc3? TypeError: Object function app(req, res){ app.handle(req, res); } has no method 'register'
Drew Noakes

1
@enyo, bạn đã bỏ lỡ điểm của kiến ​​trúc hấp. Khi mẫu là trình điều khiển / khung nhìn (hoặc / bộ xử lý / khung nhìn, cho dù kiến ​​trúc cụ thể của bạn là gì), bạn không thể đi chệch khỏi đó với mô hình tiện ích mở rộng đã lỗi thời. Bạn cần coi HTML của mình là nội dung được hiển thị như mọi thứ khác. Giữ nó KHÔ, anh bạn.
David Betz

22
app.get('/', function (req, res) {
res.sendfile(__dirname + '/public/index.html');
});

5
sendfile không phải là bộ đệm trong chế độ sản xuất nên đây không phải là một giải pháp tốt.
Teo Choong Ping

1
@SeymourCakes Vui lòng sửa lỗi cho tôi nếu tôi sai, nhưng tôi nghĩ sendFile hiện hỗ trợ bộ nhớ đệm: devdocs.io/express/index#res.sendFile
KhoPhi

19

Nếu bạn đang sử dụng express@~3.0.0, hãy thay đổi dòng bên dưới từ ví dụ của bạn:

app.use(express.staticProvider(__dirname + '/public'));

đến một cái gì đó như thế này:

app.set("view options", {layout: false});
app.use(express.static(__dirname + '/public'));

Tôi đã làm nó như được mô tả trên trang api express và nó hoạt động như sự quyến rũ. Với thiết lập đó, bạn không phải viết mã bổ sung để nó trở nên đủ dễ sử dụng cho sản xuất hoặc thử nghiệm vi mô của bạn.

Mã đầy đủ được liệt kê dưới đây:

var express = require('express');
var app = express.createServer();

app.set("view options", {layout: false});
app.use(express.static(__dirname + '/public'));

app.get('/', function(req, res) {
    res.render('index.html');
});

app.listen(8080, '127.0.0.1')

1
Tại sao bạn lặp lại app.use(express.static(__dirname + '/public'));sau khi bạn khởi động máy chủ app.listen?
fatuhoku

2
Điều gì khác biệt khi phục vụ trang html dưới dạng tĩnh so với chỉ tải trang không tĩnh bằng express?
Tích cực,

14

Tôi cũng phải đối mặt với vấn đề tương tự trong express 3.Xnode 0.6.16. Các giải pháp đưa ra ở trên sẽ không hoạt động cho phiên bản mới nhất express 3.x. Họ loại bỏ app.registerphương thức và thêm app.enginephương thức. Nếu bạn đã thử giải pháp trên, bạn có thể gặp phải lỗi sau.

node.js:201
        throw e; // process.nextTick error, or 'error' event on first tick
              ^
TypeError: Object function app(req, res){ app.handle(req, res); } has no method 'register'
    at Function.<anonymous> (/home/user1/ArunKumar/firstExpress/app.js:37:5)
    at Function.configure (/home/user1/ArunKumar/firstExpress/node_modules/express/lib/application.js:399:61)
    at Object.<anonymous> (/home/user1/ArunKumar/firstExpress/app.js:22:5)
    at Module._compile (module.js:441:26)
    at Object..js (module.js:459:10)
    at Module.load (module.js:348:31)
    at Function._load (module.js:308:12)
    at Array.0 (module.js:479:10)
    at EventEmitter._tickCallback (node.js:192:40)

Để thoát khỏi thông báo lỗi. Thêm dòng sau vàoapp.configure function

app.engine('html', require('ejs').renderFile);

Lưu ý: bạn phải cài đặt ejscông cụ mẫu

npm install -g ejs

Thí dụ:

app.configure(function(){

  .....

  // disable layout
  app.set("view options", {layout: false});

  app.engine('html', require('ejs').renderFile);

....

app.get('/', function(req, res){
  res.render("index.html");
});

Lưu ý: Giải pháp đơn giản nhất là sử dụng mẫu ejs làm công cụ xem. Ở đó bạn có thể viết HTML thô trong * .ejs xem tệp.


3
Bạn có phải cài đặt ejstrên toàn cầu?
Drew Noakes

nó nói với tôi rằng nó không thể tìm thấy tệp 'index.html'
MetaGuru

9

cấu trúc thư mục:

.
├── index.html
├── node_modules
   ├──{...}
└── server.js

server.js

var express = require('express');
var app = express();

app.use(express.static('./'));

app.get('/', function(req, res) {
    res.render('index.html');
});

app.listen(8882, '127.0.0.1')

index.html

<!DOCTYPE html>
<html>
<body>

<div> hello world </div>

</body>
</html>

đầu ra:

Chào thế giới


7

Nếu bạn không cần phải sử dụng các quan điểm mục, Đơn giản chỉ cần di chuyển html tập tin đến công chúng mục bên dưới.

và sau đó, thêm dòng này vào app. thông minh thay vì '/ lượt xem'.

server.use (express.static (__ dirname + '/ công khai'));

5

Để hiển thị trang Html trong nút, hãy thử như sau,

app.set('views', __dirname + '/views');

app.engine('html', require('ejs').renderFile);
  • Bạn cần cài đặt ejsmô-đun thông qua npmnhư:

       npm install ejs --save

Giải pháp này đã làm việc cho tôi. Mặc dù tôi đã thử tùy chọn tĩnh quá. Bạn có thể giải thích cơ chế đằng sau nó. Cảm ơn!
nghiệt

4

Đối với dự án của tôi, tôi đã tạo ra cấu trúc này:

index.js
css/
    reset.css
html/
    index.html

Mã này phục vụ index.html cho /các yêu cầu và reset.css cho /css/reset.csscác yêu cầu. Đủ đơn giản, và phần tốt nhất là nó tự động thêm các tiêu đề bộ đệm .

var express = require('express'),
    server = express();

server.configure(function () {
    server.use('/css', express.static(__dirname + '/css'));
    server.use(express.static(__dirname + '/html'));
});

server.listen(1337);

3

1) Cách tốt nhất là đặt thư mục tĩnh. Trong tệp chính của bạn (app.js | server.js | ???):

app.use(express.static(path.join(__dirname, 'public')));

công khai / css / form.html
công khai / css / style.css

Sau đó, bạn nhận được tệp tĩnh từ thư mục "công khai":

http://YOUR_DOMAIN/form.html
http://YOUR_DOMAIN/css/style.css

2)

Bạn có thể tạo bộ đệm tập tin của bạn.
Sử dụng phương thức fs.readFileSync

var cache = {};
cache["index.html"] = fs.readFileSync( __dirname + '/public/form.html');

app.get('/', function(req, res){    
    res.setHeader('Content-Type', 'text/html');
    res.send( cache["index.html"] );                                
};);

không tệ! đây là một bản demo đầy đủ https://gist.github.com/xgqfrms-GitHub/7697d5975bdffe8d474ac19ef906e906
xgqfrms

3

Với Express 4.0.0, điều duy nhất bạn phải làm là nhận xét 2 dòng trong app.js:

/* app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade'); */ //or whatever the templating engine is.

Và sau đó thả tệp tĩnh của bạn vào thư mục / công khai. Ví dụ: /public/index.html


3

Tôi đã thêm vào dưới 2 dòng và nó hoạt động với tôi

    app.set('view engine', 'html');
    app.engine('html', require('ejs').renderFile);

nó báo lỗi sau "Lỗi: Không thể tìm thấy mô-đun 'ejs' tại Function.Module._resolveFilename (module.js: 338: 15) tại Function.Module._load (module.js: 280: 25) tại Module.require ( module.js: 364: 17) theo yêu cầu (module.js: 380: 17) "
Lygub Org

@LygubOrg chạy npm install ejs --savetrong thư mục làm việc của bạn.
A1rPun

1
có cần thiết phải thêm một phụ thuộc chỉ để phục vụ một tệp html không?
JCarlosR

3

Hãy thử hàm res.sendFile () trong các tuyến Express.

var express = require("express");
var app     = express();
var path    = require("path");


app.get('/',function(req,res){
  res.sendFile(path.join(__dirname+'/index.html'));
  //__dirname : It will resolve to your project folder.
});

app.get('/about',function(req,res){
  res.sendFile(path.join(__dirname+'/about.html'));
});

app.get('/sitemap',function(req,res){
  res.sendFile(path.join(__dirname+'/sitemap.html'));
});

app.listen(3000);

console.log("Running at Port 3000");

Đọc tại đây: http://codeforgeek.com/2015/01/render-html-file-expressjs/


3

Tôi không muốn phụ thuộc vào ejs chỉ đơn giản là cung cấp tệp HTML, vì vậy tôi chỉ đơn giản là tự viết trình kết xuất nhỏ:

const Promise = require( "bluebird" );
const fs      = Promise.promisifyAll( require( "fs" ) );

app.set( "view engine", "html" );
app.engine( ".html", ( filename, request, done ) => {
    fs.readFileAsync( filename, "utf-8" )
        .then( html => done( null, html ) )
        .catch( done );
} );

2

Tôi đã cố gắng thiết lập một ứng dụng góc cạnh với API RESTful rõ ràng và đã truy cập trang này nhiều lần mặc dù nó không hữu ích. Đây là những gì tôi thấy rằng đã làm việc:

app.configure(function() {
    app.use(express.static(__dirname + '/public'));         // set the static files location
    app.use(express.logger('dev'));                         // log every request to the console
    app.use(express.bodyParser());                          // pull information from html in POST
    app.use(express.methodOverride());                      // simulate DELETE and PUT
    app.use(express.favicon(__dirname + '/public/img/favicon.ico'));
});

Sau đó, trong cuộc gọi lại cho các tuyến api của bạn trông giống như: res.jsonp(users);

Khung phía khách hàng của bạn có thể xử lý định tuyến. Express là để phục vụ API.

Tuyến đường nhà tôi trông như thế này:

app.get('/*', function(req, res) {
    res.sendfile('./public/index.html'); // load the single view file (angular will handle the page changes on the front-end)
});


2

Dưới đây là một bản demo đầy đủ của máy chủ tốc hành!

https://gist.github.com/xgqfrms-GitHub/7697d5975bdffe8d474ac19ef906e906

Hy vọng nó sẽ giúp cho bạn!

// simple express server for HTML pages!
// ES6 style

const express = require('express');
const fs = require('fs');
const hostname = '127.0.0.1';
const port = 3000;
const app = express();

let cache = [];// Array is OK!
cache[0] = fs.readFileSync( __dirname + '/index.html');
cache[1] = fs.readFileSync( __dirname + '/views/testview.html');

app.get('/', (req, res) => {
    res.setHeader('Content-Type', 'text/html');
    res.send( cache[0] );
});

app.get('/test', (req, res) => {
    res.setHeader('Content-Type', 'text/html');
    res.send( cache[1] );
});

app.listen(port, () => {
    console.log(`
        Server is running at http://${hostname}:${port}/ 
        Server hostname ${hostname} is listening on port ${port}!
    `);
});


1

Thêm các dòng sau vào mã của bạn

  1. Thay thế "ngọc" bằng "ejs" & "XYZ" (phiên bản) bằng "*" trong tệp pack.json

      "dependencies": {
       "ejs": "*"
      }
  2. Sau đó, trong tệp app.js của bạn Thêm mã sau đây:

    app.engine('html', require('ejs').renderFile);

    app.set('view engine', 'html');

  3. Và nhớ Giữ tất cả các tệp .HTML trong dạng xem Thư mục

Chúc mừng :)


1

Đối với html đơn giản, bạn không yêu cầu bất kỳ gói npm hoặc phần mềm trung gian nào

chỉ sử dụng cái này

app.get('/', function(req, res) {
    res.sendFile('index.html');
});

1

Thật đáng buồn khi khoảng năm 2020 vẫn chưa thể hiện một cách nào để hiển thị trang HTML mà không sử dụng sendFilephương thức của responseđối tượng. Sử dụng sendFilekhông phải là một vấn đề nhưng chuyển đối số cho nó dưới dạng path.join(__dirname, 'relative/path/to/file')không cảm thấy đúng. Tại sao người dùng nên tham gia __dirnamevào đường dẫn tệp? Nó nên được thực hiện theo mặc định. Tại sao không thể root máy chủ bằng cách mặc định thư mục dự án? Ngoài ra, việc cài đặt một phụ thuộc templating chỉ để hiển thị một tệp HTML tĩnh một lần nữa là không chính xác. Tôi không biết cách chính xác để giải quyết vấn đề, nhưng nếu tôi phải phục vụ HTML tĩnh, thì tôi sẽ làm một cái gì đó như:

const PORT = 8154;

const express = require('express');
const app = express();

app.use(express.static('views'));

app.listen(PORT, () => {
    console.log(`Server is listening at port http://localhost:${PORT}`);
});

Ví dụ trên giả định rằng cấu trúc dự án có một viewsthư mục và các tệp HTML tĩnh nằm bên trong nó. Ví dụ: giả sử, viewsthư mục có hai tệp HTML được đặt tên index.htmlabout.htmlsau đó để truy cập chúng, chúng ta có thể truy cập: localhost:8153/index.htmlhoặc chỉ localhost:8153/để tải index.htmltrang và localhost:8153/about.htmltải about.html. Chúng ta có thể sử dụng một cách tiếp cận tương tự để phục vụ ứng dụng phản ứng / góc cạnh bằng cách lưu trữ các tạo phẩm trong viewsthư mục hoặc chỉ sử dụng dist/<project-name>thư mục mặc định và định cấu hình nó trong máy chủ js như sau:

app.use(express.static('dist/<project-name>'));

0

Tôi muốn cho phép các yêu cầu "/" được xử lý theo tuyến Express nơi trước đó chúng đã được xử lý bởi phần mềm trung gian thống kê. Điều này sẽ cho phép tôi hiển thị phiên bản thường của index.html hoặc phiên bản được tải kết hợp + mã hóa và CSS được rút gọn, tùy thuộc vào cài đặt ứng dụng. Lấy cảm hứng từ câu trả lời của Andrew Homeyer's , tôi quyết định kéo các tệp HTML của mình - chưa sửa đổi - vào thư mục chế độ xem, định cấu hình Express như vậy

   app.engine('html', swig.renderFile);
   app.set('view engine', 'html');
   app.set('views', __dirname + '/views');  

Và tạo ra một trình xử lý tuyến đường như vậy

 app.route('/')
        .get(function(req, res){
            if(config.useConcatendatedFiles){
                return res.render('index-dist');
            }
            res.render('index');       
        });

Điều này làm việc khá tốt.


0

Trong server.js, vui lòng bao gồm

var express = require("express");
var app     = express();
var path    = require("path");


app.get('/',function(req,res){
  res.sendFile(path.join(__dirname+'/index.html'));
  //__dirname : It will resolve to your project folder.
});

0

Nếu bạn đang cố gắng phân phát một tệp HTML mà ALREADY có tất cả nội dung bên trong nó, thì nó không cần phải được 'hiển thị', nó chỉ cần được 'phục vụ'. Kết xuất là khi bạn cập nhật máy chủ hoặc tiêm nội dung trước khi trang được gửi tới trình duyệt và nó yêu cầu các phụ thuộc bổ sung như ejs, như các câu trả lời khác hiển thị.

Nếu bạn chỉ muốn hướng trình duyệt đến một tệp dựa trên yêu cầu của họ, bạn nên sử dụng res.sendFile () như thế này:

const express = require('express');
const app = express();
var port = process.env.PORT || 3000; //Whichever port you want to run on
app.use(express.static('./folder_with_html')); //This ensures local references to cs and js files work

app.get('/', (req, res) => {
  res.sendFile(__dirname + '/folder_with_html/index.html');
});

app.listen(port, () => console.log("lifted app; listening on port " + port));

Bằng cách này, bạn không cần phụ thuộc bổ sung ngoài thể hiện. Nếu bạn chỉ muốn máy chủ gửi các tệp html đã tạo của mình, thì ở trên là một cách rất nhẹ để làm như vậy.


0

index.js

var express = require('express');
var app = express();
app.use(express.static(__dirname + '/public'));


app.get('/', function(req, res) {
    res.render('index.html');
});


app.listen(3400, () => {
    console.log('Server is running at port 3400');
})

Đặt tệp index.html của bạn vào thư mục công cộng

<!DOCTYPE html>
<html>
<head>
    <title>Render index html file</title>
</head>
<body>
    <h1> I am from public/index.html </h1>
</body>
</html>

Bây giờ hãy chạy đoạn mã sau trong thiết bị đầu cuối của bạn

nút index.js


-1

Tôi thường sử dụng cái này

app.configure(function() {
    app.use(express.static(__dirname + '/web'));
});

Hãy cẩn thận vì điều đó sẽ chia sẻ mọi thứ trong thư mục / web.

Tôi hy vọng nó sẽ giúp


-2

nếu bạn đang sử dụng express express cho node.js

cài đặt npm ejs

sau đó thêm tập tin cấu hình

app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router)

;

kết xuất trang từ mô-đun xuất khẩu form.js có tệp html trong thư mục lượt xem với phần mở rộng của tên tệp ejs là form.html.ejs

sau đó tạo form.js

res.render('form.html.ejs');


Cái mớ hỗn độn này là gì?
Vighnesh Raut
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.