API 距离矩阵仅在 Javascript 中调用

Posted

技术标签:

【中文标题】API 距离矩阵仅在 Javascript 中调用【英文标题】:API distance matrix Call in Javascript alone 【发布时间】:2019-11-15 09:19:54 【问题描述】:

所以我是一个非常初学者的程序员,试图了解如何使用纯 javascript 从 Google 距离矩阵 API 调用/获取数据。

下面是我的代码

https = require('https')

function getDistance(app)

    console.log('testing1');
    let defaultPath = 'maps.googleapis.com/maps/api/distancematrix/json?units=metric';
    let APIKey = '&key=<API KEY HERE>';
    let origin = 'Tampines Avenue 1, Temasek Polytechnic';
    let destination = 'Tampines Central 5, Tampines Mall';
    let newPath = defaultPath+ '&origins=' + origin + '&destinations=' +destination + APIKey;

    console.log('https://'+ newPath); //this prints the correct path

https.get('https://'+ newPath, (res) => //i assume the problem begins here?

  console.log('testing2')//doesnt print

  let body = ''; //no idea what this does. Copied from a school lab sheet

  res.on('data', (d) =>  
    console.log('testing3') //this doesn't print
    let response = JSON.parse(body);

    let distance = response.rows[0].elements.distance.text //are these correct?
    let travelTime = response.rows[0].elements.duration.text 

    console.log(distance) //doesnt print
    console.log(response.rows[0]) //doesnt print

    app.add('distance between is ' + distance + '. Time taken is ' + travelTime);
    console.log(response);
  );
);

我很确定 'https://'+ newPath 是正确的,因为它打印在 console.log 中

然后将链接扔到浏览器中 我得到了这个结果

所以有人可以向我解释我做错了什么吗? 哦,还有,不知道这是否有必要,但我在 dialogflow.cloud.google.com 中作为我的任务的聊天机器人这样做

这是我得到的错误

错误:没有为平台定义响应:未定义于 WebhookClient.send_ (/srv/node_modules/dialogflow-fulfillment/src/dialogflow-fulfillment.js:428:13) 承诺。那么 (/srv/node_modules/dialogflow-fulfillment/src/dialogflow-fulfillment.js:246:38) 在 process._tickDomainCallback (内部/进程/next_tick.js:229:7)

【问题讨论】:

你能告诉我们问题是什么吗? @LajosArpad “问题从这里开始”在代码的 cmets 中说明。 “https.get('https://'+ newPath, (res) =>" 您是在基于浏览器的 JavaScript 中还是在基于服务器的 NodeJS 中执行此操作?你会得到什么错误?你知道如何检查错误吗? “没有任何效果”不是我们可以解决的问题……我们需要有关错误消息的具体细节,或程序某些意外行为的描述。 这是我得到的错误错误:没有为平台定义响应:未定义在 WebhookClient.send_ (/srv/node_modules/dialogflow-fulfillment/src/dialogflow-fulfillment.js:428:13) 处promise.then (/srv/node_modules/dialogflow-fulfillment/src/dialogflow-fulfillment.js:246:38) at at process._tickDomainCallback (internal/process/next_tick.js:229:7) 【参考方案1】:

我在 GitHub 上发现了一个类似的问题:https://github.com/dialogflow/dialogflow-fulfillment-nodejs/issues/22

解决办法是

好的,这就是我为使其正常工作所做的工作。

我使用 request-promise-native 而不是 http 来进行 AJAX 调用。

const rp = require('request-promise-native');

我从 rp 返回的承诺的处理程序返回了一个承诺。

return rp(options).then(data =>  // Extract relevant details from data. // Add it to the agent. agent.add('Here's the data: ', JSON.stringify(data)); return Promise.resolve(agent); );

完整代码是

'use strict';

const express = require('express');
const bodyParser = require('body-parser');
const rp = require('request-promise-native');

const  WebhookClient  = require('dialogflow-fulfillment');
const  Card, Suggestion  = require('dialogflow-fulfillment');
const  Carousel  = require('actions-on-google');

process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements

const imageUrl = 'https://developers.google.com/actions/images/badges/XPM_BADGING_GoogleAssistant_VER.png';
const imageUrl2 = 'https://lh3.googleusercontent.com/Nu3a6F80WfixUqf_ec_vgXy_c0-0r4VLJRXjVFF_X_CIilEu8B9fT35qyTEj_PEsKw';
const linkUrl = 'https://assistant.google.com/';
const API_KEY = 'YOUR-API-KEY-HERE';

const server = express();

server.use(
  bodyParser.urlencoded(
    extended: true
  )
);
server.use(bodyParser.json());

server.post('/dialog-flow-fulfillment', (request, response) => 
  const agent = new WebhookClient( request, response );

  function googleAssistantOther(agent) 
    let conv = agent.conv();
    conv.ask(`Sure! Details about $agent.parameters.movie coming your way!`);
    return getMovieDataFromOMDb(agent.parameters.movie).then(movie => 
      conv.ask(`Okay! So there you go.`);
      conv.ask(new Card(
        title: `$movie.Title($movie.Year)`,
        imageUrl: movie.Poster,
        text: `$movie.Rated | $movie.Runtime | $movie.Genre | $movie.Released ($movie.Country)`,
        buttonText: 'Website',
        buttonUrl: movie.Website || `https://www.imdb.com/title/$movie.imdbID`
      ));
      conv.ask(new Suggestion(`More details`));
      conv.ask(new Suggestion(`Another movie`));
      agent.add(conv);
      return Promise.resolve(agent);
    );
  

  function welcome(agent) 
    agent.add(`Welcome to my agent!`);
  

  function fallback(agent) 
    agent.add(`I didn't understand`);
    agent.add(`I'm sorry, can you try again?`);
  

  function getMovieDetailsOther(agent) 
    return getMovieDataFromOMDb(agent.parameters.movie).then(movie => 
      // const responseDataToSend = `$movie.Title is a $
      //   movie.Actors
      //  starer $movie.Genre movie, released in $
      //   movie.Year
      // . It was directed by $movie.Director`;
      // console.log(`Generated response as $responseDataToSend`);
      // agent.add(responseDataToSend);

      agent.add(`Okay! So there you go.`);
      agent.add(new Card(
        title: `$movie.Title($movie.Year)`,
        imageUrl: movie.Poster,
        text: `$movie.Rated | $movie.Runtime | $movie.Genre | $movie.Released ($movie.Country)`,
        buttonText: 'Website',
        buttonUrl: movie.Website || `https://www.imdb.com/title/$movie.imdbID`
      ));
      agent.add(new Suggestion(`More details`));
      agent.add(new Suggestion(`Another movie`));
      return Promise.resolve(agent);
    , error => 
      console.log(`Got an error as $error`);
      agent.add(`Sorry bout that! An error prevented getting data for: $agent.parameters.movie || 'the requested movie'`
      );
    )
    .catch(function (err) 
      console.log(`Caught an err as $err`);
      agent.add(err);
    );

    // agent.add(`This message is from Dialogflow's Cloud Functions for Firebase editor!`);
    // const newCard = new Card(
    //     title: `Title: this is a card title`,
    //     imageUrl: imageUrl,
    //     text: `This is the body text of a card.  You can even use line\n  breaks and emoji! ?`,
    //     buttonText: 'This is a button',
    //     buttonUrl: linkUrl
    // );
    // // newCard.setPlatform('facebook');
    // agent.add(newCard);
    // agent.add(new Suggestion(`Quick Reply`));
    // agent.add(new Suggestion(`Suggestion`));
    // agent.setContext( name: 'weather', lifespan: 2, parameters:  city: 'Rome' );
  

  function moreDetailsOther(agent) 
    return getMovieDataFromOMDb(agent.parameters.movie).then(movie => 
      agent.add(`Okay! I've got you covered on this too.`);
      agent.add(`So the $movie.Actors starer $movie.Type is produced by $movie.Production, is directed by $movie.Director`);
      agent.add(`It $movie.Awards. It's available in $movie.Language`);
      agent.add(`Written by $movie.Writer, it plots $movie.Plot`);
      agent.add(new Suggestion(`Stats on the movie`));
      agent.add(new Suggestion(`Another movie`));
      return Promise.resolve(agent);
    , error => 
      console.log(`Got an error as $error`);
      agent.add(`Sorry bout that! An error prevented getting data for: $agent.parameters.movie || 'the requested movie'`
      );
    )
    .catch(function (err) 
      console.log(`Caught an err as $err`);
      agent.add(err);
    );
  

  function movieStatsOther(agent) 
    return getMovieDataFromOMDb(agent.parameters.movie).then(movie => 
      let ratingDetails = `$movie.Title scored `;
      movie.Ratings.forEach(rating => 
        ratingDetails += `$rating.Value on $rating.Source `
      );
      agent.add(`Sure! Here are the stats.`);
      agent.add(ratingDetails);
      agent.add(new Suggestion(`Another movie`));
      return Promise.resolve(agent);
    , error => 
      console.log(`Got an error as $error`);
      agent.add(`Sorry bout that! An error prevented getting data for: $agent.parameters.movie || 'the requested movie'`
      );
    )
    .catch(function (err) 
      console.log(`Caught an err as $err`);
      agent.add(err);
    );
  

  function getMovieDataFromOMDb(movieName) 
    const movieToSearch = movieName || 'The Godfather';
    const options = 
      uri: 'https://www.omdbapi.com/',
      json: true,
      qs: 
        t: movieToSearch,
        apikey: API_KEY
      
    ;
    return rp(options);
  

  // Run the proper handler based on the matched Dialogflow intent
  let intentMap = new Map();
  intentMap.set('Default Welcome Intent', welcome);
  intentMap.set('Default Fallback Intent', fallback);
  if (agent.requestSource === agent.ACTIONS_ON_GOOGLE) 
    intentMap.set(null, googleAssistantOther);
    // intentMap.set('More Details', googleAssistantMoreDetails);
    // intentMap.set('Movie Stats', googleAssistantMovieStats);
   else 
    intentMap.set('Get Movie Details', getMovieDetailsOther);
    intentMap.set('More Details', moreDetailsOther);
    intentMap.set('Movie Stats', movieStatsOther);
  
  agent.handleRequest(intentMap);
);

server.listen(process.env.PORT || 8000, () => 
  console.log('Server is up and running...');
);

Codepen:https://codepen.io/siddajmera/pen/eraNLW?editors=0010

【讨论】:

当我使用这个“const rp = require('request-promise-native');”时出现错误错误说“他的云函数部署失败:加载用户代码时函数失败。错误消息:文件 index.js 中的代码无法加载。您是否在 package.json 依赖项中列出了所有必需的模块?详细的堆栈跟踪:错误:找不到模块“request-promise-native”” @CobenYap 请看一下我现在给你的链接中描述的步骤。那里描述了安装步骤:github.com/request/request-promise-native【参考方案2】:

您没有显示所有代码,但看起来 getDistance() 是您在未显示的代码中注册的 Intent Handler 函数。

如果是这样,并且您正在对 API 进行异步调用,则需要返回一个 Promise 以表明您正在等待 HTTP 调用完成,然后再发送结果。

如果没有 Promise,函数会在使用 http.get() 进行调用后立即完成,但不会为使用 app.add() 的响应设置任何内容。

虽然可以将基于事件的调用(您现在正在做的事情)转换为 Promise,但如果您不熟悉它并不容易,并且有更好的解决方案。

使用像request-promise 这样的包(更可能是 request-promise-native - 它使用相同的语法,但 request-promise 有文档)要容易得多。这样,您将返回由 http 调用生成的 Promise,并在它的 then() 子句中调用 app.add()

我还没有测试过,但它可能看起来像这样:

const rp = require('request-promise-native');

function getDistance(app)

    console.log('testing1');
    let defaultPath = 'maps.googleapis.com/maps/api/distancematrix/json?units=metric';
    let APIKey = '&key=<API KEY HERE>';
    let origin = 'Tampines Avenue 1, Temasek Polytechnic';
    let destination = 'Tampines Central 5, Tampines Mall';
    let newPath = defaultPath+ '&origins=' + origin + '&destinations=' +destination + APIKey;
    let url = 'https://'+newPath;

    console.log(url);

    rp.get(url)
      .then( response => 
        console.log(response);
        let distance = response.rows[0].elements.distance.text
        let travelTime = response.rows[0].elements.duration.text 

        app.add('distance between is ' + distance + '. Time taken is ' + travelTime);
      )
      .catch( err => 
        console.log( err );
        app.add('Something went wrong.');
      );

;

【讨论】:

当我使用“const rp = require('request-promise-native');”时出现错误错误说“他部署您的云功能失败:加载用户代码时功能失败。错误消息:无法加载文件 index.js 中的代码。您是否在 package.json 依赖项中列出了所有必需的模块?详细的堆栈跟踪:错误:找不到模块“request-promise-native”” 正如错误提示 - 您需要在 package.json 文件中列出包依赖项。

以上是关于API 距离矩阵仅在 Javascript 中调用的主要内容,如果未能解决你的问题,请参考以下文章

如何以正确的方式在 IOS SWIFT 3 中解析 Google 距离矩阵 API JSON

将纬度和经度放入距离矩阵,python中的google map API

face++ API接口调用

仅在每个项目完成其方法调用后才返回

如何仅在 Django Rest Framework 中的另一个 API 方法中调用 API POST 方法

仅在 javascript 循环完成后执行 ajax 调用