#node.js #express #meta-tags
#node.js #экспресс #мета-теги
Вопрос:
У меня есть ресурс, который содержит поле URL, введенное пользователем. Я пытаюсь использовать этот пакет: https://github.com/mozilla/page-metadata-parser чтобы получить заголовок и описание, связанные с URL-адресом, и сохранить их в базе данных при создании.
Я добавил код, смоделированный в документации пакета, в запрос post в Express, и ошибок нет, новая закладка создана, но значения метаданных не возвращаются.
Вот моя модель:
const mongoose = require('mongoose');
const { Schema } = mongoose;
const BookmarksSchema = new Schema({
userId: {
type: Schema.Types.ObjectId,
required: true
},
url: {
type: String,
trim: true,
required: true
},
...
title: {
type: String,
trim: true,
required: false
},
description: {
type: String,
trim: true,
required: false
}
});
mongoose.model('Bookmarks', BookmarksSchema);
мой метод создания:
const mongoose = require('mongoose');
const passport = require('passport');
const router = require('express').Router();
const auth = require('../auth');
const Bookmarks = mongoose.model('Bookmarks');
router.post('/', auth.required, (req, res, next) => {
const userId = req.user.id;
const bookmark = req.body.bookmark;
if (!bookmark.url) {
return res.status(422).json({
errors: {
url: 'is required',
},
});
}
const { getMetadata } = require('page-metadata-parser');
const domino = require('domino');
const url = bookmark.url;
const response = fetch(url);
const html = response.text();
const doc = domino.createWindow(html).document;
const metadata = getMetadata(doc, url);
bookmark.userId = userId;
bookmark.title = metadata.title;
bookmark.description = metadata.description;
const finalBookmark = new Bookmarks(bookmark);
return finalBookmark.save()
.then(() => res.json({ bookmark: finalBookmark }));
});
и package.json:
{
"name": "server",
"version": "1.0.0",
"description": "",
"main": "app.js",
"dependencies": {
"body-parser": "^1.18.3",
"cors": "^2.8.5",
"domino": "^2.1.3",
"errorhandler": "^1.5.0",
"express": "^4.16.4",
"express-jwt": "^5.3.1",
"express-session": "^1.15.6",
"jsonwebtoken": "^8.5.1",
"mongoose": "^5.4.20",
"morgan": "^1.9.1",
"page-metadata-parser": "^1.1.3",
"passport": "^0.4.0",
"passport-local": "^1.0.0",
"path": "^0.12.7"
},
"devDependencies": {},
"scripts": {
"test": "echo "Error: no test specified" amp;amp; exit 1",
"dev": "nodemon app"
},
"author": "",
"license": "ISC"
}
Комментарии:
1. Взглянул на документацию, и я увидел, что
fetch(url)
вызову предшествует ключевоеawait
слово . Попробуйте вставить это в свой код и запустить его снова. Я готов поспорить, чтоfetch
это асинхронный метод, который требует, чтобы вы использовалиawait
для разрешения обещания, прежде чем двигаться вперед в коде.2. Сначала я это сделал, но куда мне нужно поместить
async
вызов?3. Ключевое
async
слово будет использоваться при объявлении функции анонимного обратного вызова в маршрутизаторе. Выглядит примерно7
так, как раньше(req, res, next)
. Введите это ключевое слово и посмотрите, работает ли оно.4. Это работает. Спасибо! Я изменил запрос post на:
router.post('/', auth.required, async function (req, res, next) {
. Затем мне пришлось добавить модуль выборки узлов. Вы мне очень помогли. Если вы дадите этот ответ, я приму его.5. Рад, что это работает для вас. Пошел дальше и опубликовал немного более подробный ответ с большим количеством кода, чтобы позже это помогло большему количеству людей, которые его просматривают. Счастливого кодирования!!
Ответ №1:
Публикуем ответ здесь, чтобы мы могли пометить ответ как правильный.
Ошибка возникла из-за того, что вызов fetch()
был асинхронным вызовом, и ключевое await
слово не использовалось. Пример на сайте NPM, найденный здесь:
https://www.npmjs.com/package/page-metadata-parser
Показывает, что они использовались await
при fetch()
вызове. Чтобы использовать await
функцию анонимного обратного вызова, перед функцией, которая начинается с (req, res, next)
, должно быть ключевое async
слово. Затем вызов должен выглядеть следующим образом:
router.post('/', auth.required, async (req, res, next) => {
// Do your stuff here as before.
const url = bookmark.url;
const response = await fetch(url);
const html = response.text();
const doc = domino.createWindow(html).document;
const metadata = getMetadata(doc, url);
// Finish stuff here.
});
Теперь ответ заполняется, и программа ожидает завершения fetch
вызова, прежде чем двигаться вперед, заполняя оставшиеся переменные и получая возможность получать метаданные.