【问题标题】:Why is my Meteor API call throwing an exception?为什么我的 Meteor API 调用会引发异常?
【发布时间】:2016-01-24 00:00:28
【问题描述】:

我有以下代码(基于“Meteor In Action”的第 242 和 243 页)尝试调用外部 API:

流星方法:

Meteor.methods({
  . . .
  'getTextAddrAsEmailAddr': function(phone) {
    this.unblock;
    var apiUrl = 'http://www.xminder.com/number.check.php?number=' + phone;
    var response = Meteor.wrapAsync(apiCall) (apiUrl);
    return response;
  }
});

“专用功能”:

var apiCall = function (apiUrl, callback) {
  try {
    var response = HTTP.get(apiUrl).data;
    callback(null, response);
  } catch (error) {
    if (error.response) {
      var errorCode = error.response.data.code;
      var errorMessage = error.response.data.message;
    } else {
      var errorCode = 500;
      var errorMessage = 'Cannot access the API';
    }
    var myError = new Meteor.Error(errorCode, errorMessage);
    callback(myError, null);
  }
}

我如何称呼它(一个 Meteor 方法调用另一个):

Meteor.methods({
  'insertPerson': function(firstname, lastname, streetaddr1, streetaddr2, placename, stateorprov, zipcode, emailaddr, phone, notes) {
    console.log('insertPerson reached'); // TODO: Remove before deploying
    check(firstname, String);
    . . .
    console.log('phone is ' + phone);
    var textAddrAsEmailAddr = Meteor.call("getTextAddrAsEmailAddr", phone, function(error, result) {
      console.log("textAddrAsEmailAddr is " + textAddrAsEmailAddr);
      console.log(result);
    })
    console.log('textAddrAsEmailAddr is ' + textAddrAsEmailAddr);
    . . .

(Chrome)浏览器控制台输出:

reached addPerson.submit form
methods.js:29 insertPerson reached
methods.js:41 phone is 2624908739
debug.js:41 Exception in callback of async function Error: Cannot access the API [500]
    at apiCall (http://localhost:3000/app/both/methods.js?55690625ac0aa28550112db1c63d2b8912cc3410:30:19)
    at http://localhost:3000/packages/meteor.js?9730f4ff059088b3f7f14c0672d155218a1802d4:195:23
    at Meteor.methods.getTextAddrAsEmailAddr (http://localhost:3000/app/both/methods.js?55690625ac0aa28550112db1c63d2b8912cc3410:82:45)
    at http://localhost:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:3911:25
    at _.extend.withValue (http://localhost:3000/packages/meteor.js?9730f4ff059088b3f7f14c0672d155218a1802d4:971:17)
    at _.extend.apply (http://localhost:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:3902:54)
    at _.extend.call (http://localhost:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:3780:17)
    at Meteor.methods.insertPerson (http://localhost:3000/app/both/methods.js?55690625ac0aa28550112db1c63d2b8912cc3410:52:38)
    at http://localhost:3000/packages/ddp-client.js?250b63e6c919c5383a0511ee4efbf42bb70a650f:3911:25
    at _.extend.withValue (http://localhost:3000/packages/meteor.js?9730f4ff059088b3f7f14c0672d155218a1802d4:971:17)
methods.js:50 textAddrAsEmailAddr is undefined
methods.js:51 undefined
methods.js:53 textAddrAsEmailAddr is undefined

命令提示符输出:

I20151024-07:23:43.999(-7)? insertPerson reached
I20151024-07:23:44.021(-7)? phone is 2624908739
I20151024-07:23:44.641(-7)? textAddrAsEmailAddr is undefined
I20151024-07:23:44.649(-7)? null
I20151024-07:23:44.649(-7)? textAddrAsEmailAddr is undefined

所以结果是,我的专用函数的 catch 块被击中。为什么?我可以直接在浏览器中输入ApiUrl(http://www.xminder.com/number.check.php?number=2624908739),得到如下结果:

{"success":true,"data":{"number":"2624908739","status":"YES","carrier_name":"ATT Mobility","carrier_id":"","sms_address":"2624908739@txt.att.net","mms_address":"2624908739@mms.att.net"}}

我想要 sms_address 值,特别是;为什么我访问此响应的尝试失败了?

更新

我把代码改成这样:

var apiCall = function (apiUrl, callback) {
  try {
    var response = HTTP.get(apiUrl).data;
    callback(null, response);
  }
  // catch (error) {
  //   if (error.response) {
  //     var errorCode = error.response.data.code;
  //     var errorMessage = error.response.data.message;
  //   }
  //   else {
  //     // var errorCode = 500;
  //     var errorCode = error.response.code;
  //     // var errorMessage = 'Cannot access the API';
  //     var errorMessage = error.response.message;
  //   }
  //   var myError = new Meteor.Error(errorCode, errorMessage);
  //   callback(myError, null);
  // }
  catch (error) { console.log(error) };
}

...并在命令提示符控制台中得到相同的结果:

I20151024-08:14:57.413(-7)? insertPerson reached
I20151024-08:14:57.434(-7)? phone is 2624908741
I20151024-08:14:58.248(-7)? textAddrAsEmailAddr is undefined
I20151024-08:14:58.255(-7)? null
I20151024-08:14:58.264(-7)? textAddrAsEmailAddr is undefined

...在浏览器控制台中:

reached addPerson.submit form
methods.js:25 insertPerson reached
methods.js:37 phone is 2624908741
methods.js:20 Error: Can't make a blocking HTTP call from the client; callback required.(…)
methods.js:46 textAddrAsEmailAddr is undefined
methods.js:47 undefined
methods.js:49 textAddrAsEmailAddr is undefined

注意:将 catch 块更改为:

catch (error) {
  console.log(error)
  callback(error, null);
};

更新 2

无论如何,尝试使用这个特定的 API 可能会失败,因为在浏览器中测试一个伪造的电话号码会发出:

{"success":false,"error":"Too many requests during last 24h"}

更新 3

我将 Meteor 方法从 \both\ 文件夹移至 \server\ 文件夹,但显然收效甚微。我在浏览器控制台中只得到这个:

reached addPerson.submit form

...在命令提示符控制台中(仍然/再次):

I20151024-13:02:23.539(-7)? insertPerson reached
I20151024-13:02:23.563(-7)? phone is 2624908743
I20151024-13:02:24.399(-7)? textAddrAsEmailAddr is undefined
I20151024-13:02:24.409(-7)? null
I20151024-13:02:24.410(-7)? textAddrAsEmailAddr is undefined

...但是 Jeroen Peeter 的代码与我所拥有的不同,我不知道如何将它合并到我现有的代码中;他说:

HTTP.get(apiUrl, function (error, data){
    console.log( 'http.get ::', error, data);
});

...我有:

var apiCall = function (apiUrl, callback) {
  try {
    var response = HTTP.get(apiUrl).data;
    callback(null, response);
  }
  catch (error) {
    if (error.response) {
      var errorCode = error.response.data.code;
      var errorMessage = error.response.data.message;
    }
    else {
      var errorCode = error.response.code;
      var errorMessage = error.response.message;
    }
    var myError = new Meteor.Error(errorCode, errorMessage);
    callback(myError, null);
  }

...那么他的代码在哪里适合我的(非工作)代码?

更新 4

修改后:

var response = HTTP.get(apiUrl).data;

...到这个:

var response = JSON.parse(HTTP.get(apiUrl).content;

...我得到,在命令提示符控制台中:

=> Errors prevented startup:

   While processing files with ecmascript (for target os.windows.x86_32):
   server/methods.js:4:54: server/methods.js: Unexpected token (4:54)

=> Your application has errors. Waiting for file change.

第 4 行,字符 54 是“内容”中的最后一个“t”...???

【问题讨论】:

  • 为什么不在 catch 子句中记录错误。现在您自己将错误代码设置为 500。我无法看到实际的错误是什么。请记录错误并在此处发布。
  • 好的,我不知道具体该怎么做,但会尝试将 error.response.code 分配给 errorCode 并将 error.response.message 分配给 errorMessage。
  • 只做:..... } catch (error) { console.log(error); .....并使用错误消息更新您的问题。

标签: javascript json meteor http-get http-error


【解决方案1】:

您使用 Meteor.wrapAsync 进行外部 API 调用的方式有问题。

我会这样做(在 ecmascript2015 中)

let wrappedGetTextAddrAsEmailAddr = Meteor.wrapAsync(function (phone, callback) {
  const apiUrl = `http://www.xminder.com/number.check.php?number=${phone}`;

  HTTP.get(apiUrl, callback);
});

Meteor.methods(
{
  // Call like: Meteor.call('insertPerson', {firstname: 'Bob', ...});
  insertPerson(personData) 
  {
    let textAddrAsEmailAddr;

    console.log('insertPerson reached'); // TODO: Remove before deploying
    check(personData, Object);
    check(personData.firstname, String);
    . . .
    console.log(`phone is ${phone}`);
    textAddrAsEmailAddr = wrappedGetTextAddrAsEmailAddr(personData.phone);
    console.log(`textAddrAsEmailAddr is ${textAddrAsEmailAddr}`);
    . . .
  }
});

确保将上面的所有代码放在服务器文件夹中,或者用if (Meteor.isServer) { ... }包装它们

【讨论】:

  • 我尝试了这些更改,但在这一行的最后一个“t”上仍然失败:var response = JSON.parse(HTTP.get(apiUrl).content;
  • 您不再需要使用 var response = JSON.parse(HTTP.get(apiUrl).content; 了,上面的答案就是使 API 调用正常工作所需要的全部内容
  • 该解决方案是否适合您?我已经在我的电脑上测试过了,API 调用正常
  • 不,我从来没有让它工作,但如前所述,这对我来说是一个有争议的问题,因为 API 只能在 24 小时内接受这么多的请求。不过,我会相信你的话,它确实有效,并将其标记为正确答案。
  • 即使超过了API的请求限制,它仍然会返回某种响应,表明API调用成功。
【解决方案2】:

似乎 HTTP.get 是从客户端而不是服务器运行的。在这种情况下,无法阻止调用,因此会出现错误消息。你需要定义一个回调:

HTTP.get(apiUrl, function (error, data){
    console.log( 'http.get ::', error, data);
});

如果您不想在客户端上运行它(而且我认为您不希望那样),您需要确保在服务器上定义了您的方法。 将定义 Meteor.methods 的文件放在 server 文件夹中,或使用 if (Meteor.isServer) { ... } 包装所有 Meteor.methods 以确保仅在服务器上定义方法。

if (Meteor.isServer) { 
    Meteor.methods({
    . . .
    'getTextAddrAsEmailAddr': function(phone) {
        this.unblock;
        var apiUrl = 'http://www.xminder.com/number.check.php?number=' + phone;
        var response = Meteor.wrapAsync(apiCall) (apiUrl);
        return response;
    }
});

【讨论】:

  • 好的,谢谢;我将它从两者都移到服务器上,稍后再试。
  • 尝试HTTP.get(apiUrl).content 而不是.data。 Node(和 Meteor)使用 Content-Type 标头来确定数据类型。在这种情况下,内容类型为 text/html,因此它不会尝试将其解析为 JSON,因此 .data 为空。如果您确定 API 始终返回 JSON,请执行 JSON.parse(HTTP.get(apiUrl).content)
  • 老兄,你少了一个右括号!!你甚至知道如何编写 javascript 吗?如果没有,请先开始学习。另外,我给了你正确的行,包括那个括号,所以请努力正确地复制粘贴。我感觉这样你在浪费大家的时间!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-29
相关资源
最近更新 更多