Danh sách câu hỏi của đề

Câu hỏi: SDN302 Server-Side development with NodeJS, Express, and MongoDB – Bộ ôn tập thi lại số 2

50 câu trắc nghiệm kèm lời giải của môn Server-Side development with NodeJS, Express, and MongoDB, xếp đúng thứ tự trong đề. Trang 2/3 — câu 21–40.

Danh sách câu hỏi

40/50 câuCòn 10
APassport.js is used for session-based authentication, while JWT is for token-based authentication
BPassport.js is only used in front-end apps, while JWT is back-end only
CPassport.js is faster than JWT
DThey serve the same purpose
Lời giải
Đáp án đúng: "Passport.js is used for session-based authentication, while JWT is for token-based authentication". Đây là cách phân biệt rút gọn thường dùng khi học: Passport.js là middleware xác thực cho Express, thường đi cùng express-session, serializeUser và deserializeUser để lưu người dùng đã đăng nhập vào phiên phía máy chủ; JWT (JSON Web Token) là định dạng token tự chứa được ký số, máy chủ không cần lưu trạng thái mà chỉ kiểm chữ ký ở mỗi request. Cần nói thẳng rằng hai thứ không loại trừ nhau: Passport có nhiều strategy, kể cả passport-jwt dùng chính JWT, nên chính xác hơn thì Passport là công cụ xác thực còn JWT là định dạng token; phát biểu được chọn vẫn khớp cách dùng phổ biến và là phát biểu duy nhất nêu đúng vai trò thường gặp của mỗi bên. "Passport.js is only used in front-end apps" sai vì Passport chạy phía máy chủ Node.js. "Passport.js is faster than JWT" sai vì hai thứ khác loại nên không so tốc độ được. "They serve the same purpose" sai vì một bên là cơ chế xác thực, bên kia là định dạng mang danh tính.
Mở trang câu hỏi này →
ATo serve HTML template files
BTo upload files from the client
CTo download and save files to database
DTo render dynamic content using EJS
Lời giải
Đáp án đúng: "To serve HTML template files". Phương thức res.sendFile gửi nguyên nội dung một tệp tĩnh về trình duyệt theo đường dẫn tuyệt đối (hoặc đường dẫn tương đối kèm tuỳ chọn root), tự đặt Content-Type theo đuôi tệp; cách dùng điển hình là trả về một trang HTML có sẵn, như res.sendFile với path.join(__dirname, 'index.html'). Cần nói rõ: sendFile không render template, tệp được gửi y nguyên không chèn dữ liệu nào, nên chữ template trong phương án là cách diễn đạt lỏng, nhưng đây là phương án gần nhất với việc phục vụ tệp HTML. "To upload files from the client" ngược chiều: nhận tệp từ client là việc của middleware như multer, còn sendFile gửi tệp từ máy chủ đi. "To download and save files to database" sai vì sendFile không ghi gì vào cơ sở dữ liệu. "To render dynamic content using EJS" là việc của res.render, hàm chạy template EJS với dữ liệu để sinh HTML động.
Mở trang câu hỏi này →
23Which of the following are valid ways to define a Mongoose schema with timestamps?4 lựa chọnTrung bình67% trả lời đúng
Anew Schema({ fieldName: String }, { timestamps: true })
Bnew Schema({ fieldName: { type: String, timestamps: true } })
Cnew Schema({ fieldName: String }, { timestamps: false })
Dnew Schema({ fieldName: String }).set('timestamps', true)
Lời giải

Đáp án đúng gồm hai ý: "

Lời giải
new Schema({
  fieldName: String
}

, { timestamps: true })" và "

Lời giải
new Schema({
  fieldName: String
}

).set('timestamps', true)". timestamps là tuỳ chọn của cả schema: truyền nó ở đối số thứ hai khi tạo Schema, hoặc đặt sau bằng phương thức set của schema trước khi biên dịch thành model, đều khiến Mongoose tự thêm hai trường createdAt và updatedAt rồi cập nhật chúng mỗi lần lưu. "

Lời giải
new Schema({
  fieldName: {
    type: String, timestamps: true
  }
}

)" sai vì timestamps đặt bên trong định nghĩa một trường không phải tuỳ chọn hợp lệ của SchemaType, Mongoose bỏ qua nó nên không có trường thời gian nào được thêm. "

Lời giải
new Schema({
  fieldName: String
}

, { timestamps: false })" là cú pháp hợp lệ nhưng tắt tính năng, nên schema tạo ra không có timestamps như câu hỏi yêu cầu.

Mở trang câu hỏi này →
Đề bài
const express = require('express');
const mongoose = require('mongoose');
const app = express();
app.use(express.json());

mongoose.connect('mongodb://localhost:27017/test', { useNewUrlParser: true });

Đề bài
const userSchema = new mongoose.Schema({ name: String, email: String });
const User = mongoose.model('User', userSchema);
app.post('/api/users', async (req, res) => {
  try {
    const user = await User.create(req.body);
    res.status(201).json(user);
  } catch (err) {
    res.status(400).json({ error: err.message });
  }
});
app.listen(3000);
A201 with { _id: "...", name: "Alice", email: "alice@example.com" }
B400 with { error: "Validation failed" }
C500 with { error: "Internal Server Error" }
DThrows an unhandled promise rejection
Lời giải
Đáp án đúng: "201 with { _id: "...", name: "Alice", email: "alice@example.com" }". Lần theo mã: express.json() phân tích body JSON nên req.body là đối tượng có name và email; User.create(req.body) lưu một tài liệu mới, Mongoose tự sinh _id, và vì các lệnh được đệm (buffering) cho tới khi kết nối xong nên không lỗi dù connect chưa hoàn tất lúc request tới; await trả tài liệu đã lưu rồi res.status(201).json(user) gửi mã 201 kèm tài liệu, thực tế còn có trường __v bằng 0 do Mongoose thêm. "400 with { error: "Validation failed" }" sai vì schema chỉ khai báo hai trường String, không có validator nào nên dữ liệu hợp lệ. "500 with { error: "Internal Server Error" }" sai vì khối catch chỉ trả 400, mã không có nhánh nào trả 500. "Throws an unhandled promise rejection" sai vì mọi lỗi của await đều được try/catch bắt.
Mở trang câu hỏi này →
Aimport mongodb from 'mongodb';
Brequire('mongodb');
Cinclude('mongodb');
Duse('mongodb');
Lời giải
Đáp án đúng: "require('mongodb');". Trong Node.js theo kiểu CommonJS, driver chính thức được nạp bằng require('mongodb'), thường viết const { MongoClient } = require('mongodb') để lấy lớp MongoClient dùng kết nối; câu hỏi hỏi một hàm (function) để nhập, và require là hàm có sẵn trong mỗi module CommonJS. "import mongodb from 'mongodb';" là câu lệnh import của ES module chứ không phải một hàm, chỉ dùng được khi dự án bật type module hoặc dùng đuôi .mjs. "include('mongodb');" không tồn tại trong Node.js; include là từ khoá của PHP hay chỉ thị tiền xử lý của C. "use('mongodb');" cũng không phải hàm nạp module; use gợi nhớ app.use() của Express dùng để gắn middleware.
Mở trang câu hỏi này →
APOST
BGET
CPUT
DDELETE
Lời giải
Đáp án đúng gồm hai ý: "POST" và "PUT". Trong REST, POST gửi dữ liệu tới một tập hợp như POST /books để máy chủ tạo tài nguyên mới và tự cấp id, thường trả về 201 Created; gọi lại nhiều lần sẽ tạo nhiều bản ghi nên POST không idempotent. PUT gửi biểu diễn đầy đủ tới đúng URL của một tài nguyên như PUT /books/7 để thay thế hoàn toàn trạng thái của nó; gọi lặp lại cho cùng kết quả nên PUT idempotent, và trường nào không gửi sẽ coi như bị bỏ đi (khác với PATCH chỉ sửa một phần). "GET" chỉ đọc tài nguyên, không được tạo hay thay đổi dữ liệu trên máy chủ. "DELETE" xoá tài nguyên khỏi URL đó, không tạo mới cũng không thay thế nội dung.
Mở trang câu hỏi này →
27What is the MongoDB equivalent of a "table"?4 lựa chọnTrung bình
ADocument
BField
CCollection
DSchema
Lời giải
Đáp án đúng: "Collection". Trong MongoDB, collection là nhóm các tài liệu, đóng vai trò tương đương bảng (table) của cơ sở dữ liệu quan hệ; một database chứa nhiều collection, và Mongoose ánh xạ mỗi Model tới một collection, ví dụ model User mặc định dùng collection users. Khác bảng ở chỗ các tài liệu trong cùng collection không bắt buộc có cùng tập trường. "Document" tương đương một hàng (row), tức một bản ghi BSON nằm trong collection. "Field" tương đương một cột (column), là một cặp khoá – giá trị trong tài liệu. "Schema" là bản mô tả cấu trúc tài liệu do Mongoose định nghĩa ở tầng ứng dụng; bản thân MongoDB không bắt buộc schema, và schema không phải nơi chứa dữ liệu như bảng.
Mở trang câu hỏi này →
AIaaS
BPaaS
CBaaS
DSaaS
Lời giải
Đáp án đúng: "BaaS". BaaS (Backend as a Service, phần phụ trợ như một dịch vụ) cung cấp sẵn các khối phía máy chủ như cơ sở dữ liệu, xác thực người dùng, lưu trữ tệp, thông báo đẩy, và lập trình viên gọi chúng qua API hoặc SDK mà không phải tự viết hay vận hành server; Firebase và Supabase là ví dụ quen thuộc. "IaaS" cho thuê hạ tầng thô như máy ảo, mạng, ổ đĩa, người dùng tự cài và quản lý mọi thứ phía trên. "PaaS" cung cấp nền tảng để triển khai mã ứng dụng của chính mình, như Heroku, nhưng phần backend vẫn do bạn viết. "SaaS" là phần mềm hoàn chỉnh cho người dùng cuối như Gmail, không phải bộ dịch vụ backend dành cho lập trình viên.
Mở trang câu hỏi này →
Đề bài
const express = require('express');
const app = express();
app.use('/api', (req, res, next) => {
    console.log('Middleware');
    next();
});
app.get('/api', (req, res) => res.send('API'));
app.listen(3000);
AMiddleware API
BOnly the API response if middleware skipped
CLogs middleware then processes GET handler
DCombined output from both functions
Lời giải
Đáp án đúng: "Logs middleware then processes GET handler". Lần theo mã: request GET /api khớp app.use('/api') trước tiên vì nó được khai báo trước, hàm này chạy console.log('Middleware') in Middleware ra console của server rồi gọi next(); Express tìm tiếp và gặp app.get('/api'), handler gọi res.send('API') nên client nhận phản hồi API. Phương án được chọn mô tả đúng trình tự ghi log ở middleware rồi xử lý ở handler GET. Cần nói thẳng về "Middleware API": nó gộp dòng log ở server với nội dung phản hồi HTTP thành một đầu ra, chỉ đúng nếu hiểu output là cả hai nơi, còn trình duyệt thực tế chỉ nhận API. "Only the API response if middleware skipped" sai vì middleware không bị bỏ qua: đường dẫn khớp và nó gọi next() bình thường. "Combined output from both functions" sai vì chỉ handler GET gửi phản hồi, middleware không ghi gì vào response, nên client không nhận đầu ra gộp từ cả hai hàm.
Mở trang câu hỏi này →
A“username&password”
B“username:password”
C“username_password”
D“username@password”
Lời giải
Đáp án đúng: "“username:password”". Theo cơ chế HTTP Basic Authentication, client ghép tên đăng nhập và mật khẩu bằng một dấu hai chấm, mã hoá chuỗi đó bằng Base64, rồi gửi trong header Authorization dạng Basic theo sau là chuỗi đã mã hoá; máy chủ giải Base64 và tách ở dấu hai chấm đầu tiên để lấy lại hai phần, vì thế tên đăng nhập không được chứa dấu hai chấm. Base64 chỉ là mã hoá để truyền chứ không phải mã hoá bảo mật, nên Basic Auth phải đi kèm HTTPS. "“username&password”" sai vì dấu và là ký tự ngăn tham số trong query string, không phải dấu phân cách của Basic Auth. "“username_password”" sai vì gạch dưới có thể xuất hiện trong tên đăng nhập nên không tách được. "“username@password”" sai vì @ là ký tự thường gặp trong email dùng làm tên đăng nhập, không phải dấu phân cách chuẩn.
Mở trang câu hỏi này →
31Which an asynchronous method of fs module is used to check a file exists?4 lựa chọnTrung bình67% trả lời đúng
Afs.existsFile(filePath, function(exists) { . . . } );
Bfs.exists(filePath, function(exists) { . . . } );
Cfs.fileExists(filePath, function(exists) { . . . } );
Dfs.access(filePath, fs.constants.F_OK, (err) => {...});
Lời giải

Đáp án đúng: "

Lời giải
fs.access(filePath, fs.constants.F_OK, (err) => {
  ...
}

);". fs.access kiểm tra quyền truy cập của tiến trình tới một đường dẫn; truyền cờ fs.constants.F_OK nghĩa là chỉ hỏi tệp có tồn tại hay không, và callback nhận err (thường mang mã ENOENT) khi tệp không có, nhận null khi có, đúng quy ước lỗi trước (error-first) của Node.js. Chỗ dễ tranh cãi là "

Lời giải
fs.exists(filePath, function(exists) {
  . . .
}

);": đây cũng là hàm bất đồng bộ có thật, callback nhận một giá trị boolean, nhưng tài liệu Node.js đã đánh dấu nó deprecated (ngừng khuyên dùng) từ lâu chính vì callback không theo quy ước lỗi trước, và khuyên thay bằng fs.access hoặc fs.stat; vì vậy cách chuẩn hiện nay là fs.access. "

Lời giải
fs.existsFile(filePath, function(exists) {
  . . .
}

);" không tồn tại trong module fs. "

Lời giải
fs.fileExists(filePath, function(exists) {
  . . .
}

);" cũng là tên không có trong API, gọi sẽ báo lỗi không phải hàm.

Mở trang câu hỏi này →
Arouter.delete('/comments/:id')
Brouter.get('/comments/:id')
Crouter.post('/comments/:id')
Drouter.put('/comments/:id')
Lời giải
Đáp án đúng: "router.delete('/comments/:id')". Quy ước REST gắn hành động với method HTTP: xoá tài nguyên dùng DELETE, và :id là tham số đường dẫn mà handler đọc qua req.params.id để biết bình luận nào cần xoá; trong thực tế còn truyền hàm xử lý làm đối số thứ hai, ví dụ thêm deleteComment sau đường dẫn. "router.get('/comments/:id')" dành cho đọc một bình luận, GET phải an toàn và không đổi dữ liệu. "router.post('/comments/:id')" dùng POST, vốn để tạo mới hoặc gửi dữ liệu cần xử lý, không đúng ngữ nghĩa xoá. "router.put('/comments/:id')" dùng PUT để thay thế toàn bộ hoặc cập nhật tài nguyên, không phải để xoá.
Mở trang câu hỏi này →
33Which statements about Promises in Node.js are true?4 lựa chọnTrung bình
AA Promise represents the eventual completion (or failure) of an asynchronous operation and its resulting value.
BPromises are used to handle synchronous operations.
CA Promise is in one of three states: pending, fulfilled, or rejected.
DPromises can only handle one asynchronous operation at a time.
Lời giải
Đáp án đúng gồm hai ý: "A Promise represents the eventual completion (or failure) of an asynchronous operation and its resulting value." và "A Promise is in one of three states: pending, fulfilled, or rejected.". Promise là đối tượng đại diện cho kết quả sẽ có trong tương lai của một thao tác bất đồng bộ: lúc tạo nó ở trạng thái pending, khi thao tác xong thì chuyển sang fulfilled kèm giá trị hoặc rejected kèm lý do lỗi, và đã chuyển rồi thì không đổi nữa; then, catch hay await dùng để nhận kết quả đó. "Promises are used to handle synchronous operations." sai vì mục đích của Promise là thao tác bất đồng bộ; bọc giá trị đồng bộ bằng Promise.resolve được nhưng không phải công dụng chính, và callback của then luôn chạy bất đồng bộ. "Promises can only handle one asynchronous operation at a time." sai vì có thể chạy nhiều Promise song song rồi gom chúng bằng Promise.all, Promise.allSettled hay Promise.race.
Mở trang câu hỏi này →
AThe http.createServer method is used to create a server instance.
BThe server.listen method is used to start the server and listen for incoming requests.
CThe require('http') statement is used to install the http module.
DThe npm i http command is used to require the http module in your code.
Lời giải
Đáp án đúng gồm hai ý: "The http.createServer method is used to create a server instance." và "The server.listen method is used to start the server and listen for incoming requests.". Quy trình chuẩn là nạp module có sẵn bằng require('http'), gọi http.createServer với một hàm nhận req và res để có đối tượng server, rồi gọi server.listen với số cổng để máy chủ bắt đầu lắng nghe; mỗi request tới sẽ kích hoạt hàm xử lý đã truyền. "The require('http') statement is used to install the http module." sai vì require chỉ nạp module vào mã đang chạy chứ không cài đặt gì, và http là core module có sẵn trong Node.js nên không cần cài. "The npm i http command is used to require the http module in your code." trộn lẫn hai việc: npm i là lệnh cài gói từ kho npm vào node_modules, chạy ở dòng lệnh, còn việc nạp module trong mã là của require; hơn nữa module http lõi không cần cài bằng npm.
Mở trang câu hỏi này →
Đề bài
// app.js
app.get('/', (req, res) => res.render('home', { title: 'Home' }));

// home.ejs
<h1><%= title %></h1>
A<h1>Home</h1>
B<h1><%= title %></h1>
CTemplate string if data not passed correctly
DDynamic content based on passed object
Lời giải

Đáp án đúng: "<h1>Home</h1> ". Lần theo mã: route GET / gọi res.render với tên home và đối tượng có title là Home, Express tìm tệp views/home.ejs và đưa dữ liệu cho EJS; thẻ <%= title %> là thẻ xuất giá trị có thoát ký tự HTML (escape), EJS thay nó bằng giá trị biến title là Home, nên trình duyệt nhận HTML hoàn chỉnh với thẻ h1 chứa chữ Home. "<h1><%= title %></h1> " sai vì đó là mã mẫu trước khi kết xuất; thẻ EJS không lọt nguyên ra phản hồi khi render thành công. "Template string if data not passed correctly" sai vì nếu thiếu title, EJS ném lỗi ReferenceError chứ không in lại chuỗi mẫu, và ở đây dữ liệu đã được truyền đúng. "Dynamic content based on passed object" mô tả chung bản chất của EJS nhưng không nói kết quả cụ thể, trong khi câu hỏi cần đầu ra chính xác.

Mở trang câu hỏi này →
36What is the default port for MongoDB?4 lựa chọn
A80
B3000
C27017
D8080
Lời giải
Đáp án đúng: "27017". Tiến trình mongod mặc định lắng nghe cổng TCP 27017, nên chuỗi kết nối quen thuộc là mongodb://localhost:27017; khi chạy vai trò shard hay config server thì có các cổng mặc định khác như 27018, 27019, và có thể đổi bằng tuỳ chọn port khi khởi động. "80" là cổng mặc định của HTTP cho web server, MongoDB không dùng giao thức HTTP để kết nối. "3000" là cổng mà nhiều ví dụ Express và Node.js chọn theo thói quen, không phải mặc định của MongoDB. "8080" thường dùng cho máy chủ web phụ hoặc proxy như Tomcat, cũng không liên quan MongoDB.
Mở trang câu hỏi này →
ANestJS eliminates the need for middleware for request processing
BNestJS organizes code into reusable modules with controllers and services
CNestJS automatically handles database migrations for MongoDB
DNestJS provides built-in support for real-time WebSocket communication
Lời giải
Đáp án đúng: "NestJS organizes code into reusable modules with controllers and services". Kiến trúc của NestJS xoay quanh module: mỗi lớp gắn @Module() gom controllers (nhận request), providers như service (chứa logic nghiệp vụ) cùng khai báo imports, exports, nhờ đó từng tính năng như users hay auth được đóng gói riêng, tái sử dụng và kiểm thử được nhờ dependency injection; Express thuần chỉ có router và middleware, cấu trúc thư mục do mỗi nhóm tự đặt. "NestJS eliminates the need for middleware" sai vì NestJS vẫn có middleware, mặc định chạy trên chính Express, và còn thêm guard, interceptor, pipe. "NestJS automatically handles database migrations for MongoDB" sai vì Nest không tự chạy migration; việc đó do ORM hay công cụ riêng đảm nhận. "NestJS provides built-in support for real-time WebSocket communication" có phần đúng vì Nest có gói @nestjs/websockets với gateway, nhưng đó là một tính năng phụ trợ, không phải lợi thế của kiến trúc module mà câu hỏi nhắm tới.
Mở trang câu hỏi này →
AHTTPS uses SSL/TLS to secure data transmission
BHTTP is only used for REST APIs
CHTTPS supports XML while HTTP does not
DHTTP is slower due to encryption
Lời giải
Đáp án đúng: "HTTPS uses SSL/TLS to secure data transmission". HTTPS là HTTP chạy trên một kết nối được bảo vệ bằng TLS (thế hệ sau của SSL): trước khi trao đổi dữ liệu, trình duyệt và máy chủ bắt tay, máy chủ đưa chứng chỉ số để chứng minh danh tính, hai bên thống nhất khoá rồi mã hoá toàn bộ request và response, nên kẻ nghe lén không đọc hay sửa được nội dung. HTTP thì gửi dữ liệu dạng rõ. "HTTP is only used for REST APIs" sai vì HTTP là giao thức chung của web, dùng cho trang HTML, ảnh, tệp, SOAP lẫn REST. "HTTPS supports XML while HTTP does not" sai vì cả hai đều chở được mọi định dạng nội dung như HTML, JSON, XML; khác biệt nằm ở lớp bảo mật chứ không ở định dạng. "HTTP is slower due to encryption" đảo ngược sự thật: HTTP không mã hoá gì, chính HTTPS mới tốn thêm chút chi phí bắt tay và mã hoá, dù ngày nay rất nhỏ.
Mở trang câu hỏi này →
ATo sort the documents.
BTo filter documents based on pattern matching.
CTo update multiple documents.
DTo delete a specific document.
Lời giải
Đáp án đúng: "To filter documents based on pattern matching.". Biểu thức chính quy (regex) trong truy vấn MongoDB, viết qua toán tử $regex hoặc truyền thẳng một đối tượng RegExp, cho phép lọc các tài liệu có trường chuỗi khớp một mẫu: bắt đầu bằng, chứa hoặc kết thúc bằng một chuỗi, có hoặc không phân biệt hoa thường, thường dùng cho chức năng tìm kiếm theo tên. "To sort the documents." sai vì sắp xếp là việc của sort(), regex không đổi thứ tự kết quả. "To update multiple documents." sai vì regex chỉ là điều kiện lọc; cập nhật là việc của updateMany, dù regex có thể nằm trong bộ lọc của nó. "To delete a specific document." sai tương tự: xoá do deleteOne thực hiện, còn regex thường khớp nhiều tài liệu chứ không chỉ định đúng một tài liệu.
Mở trang câu hỏi này →
AOne-to-one or one-to-many
BMany-to-many only
CNo relationship
DSQL-style joins
Lời giải
Đáp án đúng: "One-to-one or one-to-many". Population thay ObjectId bằng tài liệu được tham chiếu: trường lưu một ObjectId có ref cho quan hệ một-một, như mỗi hồ sơ trỏ tới một người dùng, còn trường là mảng ObjectId cho quan hệ một-nhiều, như một tác giả có nhiều bài viết. Nói thêm cho trọn: đặt mảng tham chiếu ở cả hai phía cũng mô phỏng được nhiều-nhiều, nhưng đó vẫn là ghép các tham chiếu một-nhiều. "Many-to-many only" sai vì chữ only loại bỏ hai trường hợp phổ biến nhất là một-một và một-nhiều. "No relationship" sai vì mục đích của ref và populate chính là liên kết tài liệu giữa các collection. "SQL-style joins" sai vì populate không nối bảng ngay trong cơ sở dữ liệu, Mongoose chạy truy vấn phụ riêng rồi ghép kết quả trong ứng dụng.
Mở trang câu hỏi này →