Попытка получить метаданные url в Express / NodeJS

#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 вызова, прежде чем двигаться вперед, заполняя оставшиеся переменные и получая возможность получать метаданные.