«res.end» не является функцией в «res.on ('end', () =>» (express. js) - PullRequest
2 голосов
/ 04 августа 2020

Я не понимаю, как показать результат json, который я получил от api на моей веб-странице

Я использую express. js + node.js и Bing API

вот мой код

const https = require('https');
const express = require("express");
const app = express();
var port = 8000;

const SUBSCRIPTION_KEY = 'xxxxxxxxxxxxxxxxxxxxx'
if (!SUBSCRIPTION_KEY) {
  throw new Error('error no keys')
}

app.use(express.static("example.com"));

function bingWebSearch(query) {
  https.get({
    hostname: 'api.cognitive.microsoft.com',
    path:     '/bing/v7.0/search?q=' + encodeURIComponent(query),
    headers:  { 'Ocp-Apim-Subscription-Key': SUBSCRIPTION_KEY },
  }, res => {
    let body = ''
    res.on('data', part => body += part)
    res.on('end', () => {

      // yes this could work and print out result json at my terminal
      console.dir(JSON.parse(body), { colors: false, depth: null })

      // but why this can not work with error msg I posted below
      res.setHeader('Content-Type', 'application/json');
      res.end(JSON.stringify({ a: 1 }));
      // I cant even output this on my webpage, and actually I want to print of course the result json

    })
    res.on('error', e => {
      console.log('Error: ' + e.message)
      throw e
    })
  })
}

app.get("/api", (req, res) => {

  const searchString = `${req.query.q}`;
  bingWebSearch(searchString);

});

app.listen(port, () => console.log('Your app is ready! Navigate to: http://localhost:' + port + '/.'));

и сообщение об ошибке здесь

/var/www/bing-web-search.js:27
  res.setHeader('Content-Type', 'application/json');
      ^
/var/www/bing-web-search.js:28
  res.end(JSON.stringify({ a: 1 }));
      ^
TypeError: res.setHeader is not a function
TypeError: res.end is not a function
    at IncomingMessage.res.on (/var/www/bing-web-search.js:31:11)
    at emitNone (events.js:111:20)
    at IncomingMessage.emit (events.js:208:7)
    at endReadableNT (_stream_readable.js:1064:12)
    at _combinedTickCallback (internal/process/next_tick.js:138:11)
    at process._tickCallback (internal/process/next_tick.js:180:9)

ps, если я перенесу строку 27,28 в app.get

app.get("/api", (req, res) => {

  const searchString = `${req.query.q}`;
  bingWebSearch(searchString);
  res.setHeader('Content-Type', 'application/json');
  res.end(JSON.stringify({ a: 1 }));

});

Они отлично работали, чтобы появиться на моей веб-странице

Так что я просто не знаю, как сделать так, чтобы мой результат также отображался на моей веб-странице

Любой совет или помощь были бы признательны, спасибо!

Ответы [ 3 ]

1 голос
/ 04 августа 2020

У вас есть две разные переменные с именами res. У них совершенно разные значения.

Определенный здесь res:

app.get("/api", (req, res) => {

… это объект, представляющий ответ, который вы собираетесь отправить от Express клиенту.

Определенный здесь res:

}, res => {

… это объект, представляющий ответ, который вы получили из Bing.

Вы пытаетесь обработать ответ от Bing, как если бы это был ответ, который вы отправляете клиенту.

Поскольку это не так, он терпит неудачу. Он не работает именно так, как вы видите, потому что API-интерфейсы для двух объектов различны.

Вам нужно поместить данные из ответа bingWebSearch(searchString); в то же место, что и объект ответа Express. Использование разных имен переменных для двух переменных res было бы неплохо идея тоже, это сделало бы код менее запутанным.

Поскольку вы используете https.get, вы можете сделать это, передав функцию обратного вызова, которая закрывает переменную Express res, но это, вероятно, Вместо этого будет проще заключить его в обещание. Было бы еще проще заменить https.get на API, который использует обещания по умолчанию (например, Ax ios).

Дополнительная литература: Как мне вернуть ответ от асинхронного вызова?

1 голос
/ 04 августа 2020
const https = require('https');
const express = require("express");
const app = express();
var port = 8000;

const SUBSCRIPTION_KEY = 'xxxxxxxxxxxxxxxxxxxxx'
if (!SUBSCRIPTION_KEY) {
  throw new Error('error no keys')
}

app.use(express.static("example.com"));

function bingWebSearch(query) {
  https.get({
    hostname: 'api.cognitive.microsoft.com',
    path:     '/bing/v7.0/search?q=' + encodeURIComponent(query),
    headers:  { 'Ocp-Apim-Subscription-Key': SUBSCRIPTION_KEY },
  }, (req, res) => {
    let body = ''
    res.on('data', part => body += part)
    res.on('end', () => {

      // yes this could work and print out result json at my terminal
      console.dir(JSON.parse(body), { colors: false, depth: null })

      // but why this can not work with error msg I posted below
      res.setHeader('Content-Type', 'application/json');
      res.end(JSON.stringify({ a: 1 }));
      // I cant even output this on my webpage, and actually I want to print of course the result json

    })
    res.on('error', e => {
      console.log('Error: ' + e.message)
      throw e
    })
  })
}

app.get("/api", (req, res) => {

  const searchString = `${req.query.q}`;
  bingWebSearch(searchString);

});

app.listen(port, () => console.log('Your app is ready! Navigate to: http://localhost:' + port + '/.'));

express возвращает ответ во втором параметре функции, а не в первом. поэтому я исправил это в строке номер 18.

1 голос
/ 04 августа 2020

Это очень базовая c концепция программирования, называемая областью действия. И вы действительно очень близки к решению. Вы можете прочитать об области видимости в Javascript здесь .

При вызове GET /api вызывается другая функция bingWebSearch(searchString). bingWebSearch имеет свой прицел. Таким образом, переменная res из GET /api там недоступна.

Кроме того, в bingWebSearch вы делаете запрос https.get, и вы также называете возвращаемое значение res.

Одним из решений может быть передача переменной res GET /api в качестве аргумента:

bingWebSearch(searchString, res)

Но тогда, конечно, вам нужно переименовать возвращаемое значение https.get. Вы могли бы назвать это response.

Это будет выглядеть так:

app.get("/api", (req, res) => {
   bingWebSearch(searchString, res);
});

function bingWebSearch(query, res) {
   https.get({
      ...
   }, response => {
      let body = ''
      response.on('data', part => body += part)
      response.on('end', () => {
         res.setHeader('Content-Type', 'application/json');
         res.end(JSON.stringify({ a: 1 }));
      }
   }
}

Другим решением было бы фактически return строку JSON из bingWebSearch, а затем вызвать res.setHeader и res.end внутри app.get("/api").

Думаю, я бы предпочел этот вариант, так как я считаю его более читаемым. Но тогда вы должны учитывать, что https.get вызывается asyn c. Так что если вы попытаетесь просто вернуть его результат, результата еще не будет. Но это топи c само по себе и выходит за рамки вашего вопроса. В ответе Квентина есть намеки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...