如何从 eBay 通知中获取数据

How to get data from eBay Notifications

我正在学习 Meteor Chef. I am using it to create a route/API with Meteor that will receive the notifications from eBay. But the problem I'm having is, the request.body that I receive from eBay is an empty object. I can see the headers it sends me just fine in the request where it has soapaction AskSellerQuestion 的教程。 (我通过提问来测试它,所以它似乎有效)

我在 eBay 通知请求中的确切位置可以找到包含通知信息的 XML?还是我以错误的方式去做?我发现 eBay 的文档不是很有帮助。

我请求的代码:

这是我的api.js

API = {

   authentication: function( apiKey ) {
      // Authenticate with the app's API Key
      var getKey = Meteor.settings.auroraAPIKey;
      if ( apiKey === getKey ) {
         return true;
      } else {
         return false;
      }

   },
   connection: function( request, key ) {
      var getRequestContents = API.utility.getRequestContents( request ),
          //apiKey             = getRequestContents.api_key,
          validUser          = API.authentication( key );

      if ( validUser ) {
         //delete getRequestContents.api_key;
         // return data
         // This object is refered to as 'connection.data'
         return { owner: 'Aurora', data: getRequestContents };
      } else {
         return { error: 401, message: "Invalid API key." };
      }
   },
   handleRequest: function( context, resource, method, key ) {
      var connection = API.connection( context.request, key );
      if ( !connection.error ) {
         API.methods[ resource ][ method ]( context, connection );
      } else {
         API.utility.response( context, 401, connection );
      }
   },

   methods: {
      ebay: {
         GET: function( context, connection ) {},
         POST: function( context, connection ) {

            // HERE: is where I want to access the request.body but it is empty

            console.log( connection.data, context.request );
            // Response of 200 is required for eBay Notifications
            API.utility.response( context, 200, connection.data );

            let soapaction = context.request.headers.soapaction;
            let split = soapaction.split( '/notification/' );
            let notification = split[ 1 ];

            EbayNotifications.insert(
               {
                  createdAt: new Date(),
                  soapaction: soapaction,
                  notification: notification
               }
            );
         },
         PUT: function( context, connection ) {},
         DELETE: function( context, connection ) {}
      }
   },

   utility: {
      getRequestContents: function( request ) {
         switch( request.method ) {
            case "GET":
               return request.query;
            case "POST":
            case "PUT":
            case "DELETE":
               return request.body;
         }
      },
      hasData: function( data ) {
         return Object.keys( data ).length > 0 ? true : false;
      },
      response: function( context, statusCode, data ) {
         context.response.setHeader( 'Content-Type', 'application/json' );
         context.response.statusCode = statusCode;
         context.response.end( JSON.stringify( data ) );
      },
      validate: function( data, pattern ) {
         return Match.test( data, pattern );
      }
   }

};

这是我的路线:

Router.route( '/api/ebay/:key', function () {
   this.response.setHeader( 'Access-Control-Allow-Origin', '*' );
   // https://api.ebay.com/ws/api.dll

   if ( this.request.method === "OPTIONS" ) {
      this.response.setHeader( 'Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept' );
      this.response.setHeader( 'Access-Control-Allow-Methods', 'POST, PUT, GET, DELETE, OPTIONS' );
      this.response.end( 'Set OPTIONS.' );
   } else {
      API.handleRequest( this, 'ebay', this.request.method, this.params.key );
   }
}, { where: 'server' });

这样就成功收到了eBay平台通知。我只是不确定在哪里访问 XML,因为 request.body 是空白的。我一直在 google 中搜索我需要的信息。 eBay 有文档:SetNotificationPreferences, Working With Platform Notifications, and Getting Notifications 我已经检查过了,但似乎对我的情况没有帮助。

再次编辑:这是我在记录请求时收到的内容:

{} { _readableState: 
   { highWaterMark: 16384,
     buffer: [],
     length: 0,
     pipes: null,
     pipesCount: 0,
     flowing: false,
     ended: false,
     endEmitted: false,
     reading: false,
     calledRead: false,
     sync: true,
     needReadable: false,
     emittedReadable: false,
     readableListening: false,
     objectMode: false,
     defaultEncoding: 'utf8',
     ranOut: false,
     awaitDrain: 0,
     readingMore: false,
     decoder: null,
     encoding: null },
  readable: true,
  domain: null,
  _events: { close: [Function] },
  _maxListeners: 10,
  socket: 
   { _connecting: false,
     _handle: 
      { fd: 32,
        writeQueueSize: 0,
        owner: [Circular],
        onread: [Function: onread],
        reading: true },
     _readableState: 
      { highWaterMark: 16384,
        buffer: [],
        length: 0,
        pipes: null,
        pipesCount: 0,
        flowing: false,
        ended: false,
        endEmitted: false,
        reading: true,
        calledRead: true,
        sync: false,
        needReadable: true,
        emittedReadable: false,
        readableListening: false,
        objectMode: false,
        defaultEncoding: 'utf8',
        ranOut: false,
        awaitDrain: 0,
        readingMore: false,
        decoder: null,
        encoding: null },
     readable: true,
     domain: null,
     _events: 
      { end: [Object],
        finish: [Function: onSocketFinish],
        _socketEnd: [Function: onSocketEnd],
        drain: [Object],
        timeout: [Function],
        error: [Function],
        close: [Object] },
     _maxListeners: 10,
     _writableState: 
      { highWaterMark: 16384,
        objectMode: false,
        needDrain: false,
        ending: false,
        ended: false,
        finished: false,
        decodeStrings: false,
        defaultEncoding: 'utf8',
        length: 0,
        writing: false,
        sync: false,
        bufferProcessing: false,
        onwrite: [Function],
        writecb: null,
        writelen: 0,
        buffer: [],
        errorEmitted: false },
     writable: true,
     allowHalfOpen: true,
     onend: [Function],
     destroyed: false,
     bytesRead: 4987,
     _bytesDispatched: 1231,
     _pendingData: null,
     _pendingEncoding: '',
     server: 
      { domain: null,
        _events: [Object],
        _maxListeners: 10,
        _connections: 6,
        connections: [Getter/Setter],
        _handle: [Object],
        _usingSlaves: false,
        _slaves: [],
        allowHalfOpen: true,
        httpAllowHalfOpen: false,
        timeout: 5000,
        _connectionKey: '4:0.0.0.0:8080' },
     _idleTimeout: 120000,
     _idleNext: 
      { _connecting: false,
        _handle: [Object],
        _readableState: [Object],
        readable: true,
        domain: null,
        _events: [Object],
        _maxListeners: 10,
        _writableState: [Object],
        writable: true,
        allowHalfOpen: false,
        onend: null,
        destroyed: false,
        bytesRead: 14384,
        _bytesDispatched: 1798,
        _pendingData: null,
        _pendingEncoding: '',
        _idleTimeout: 30000,
        _idleNext: [Object],
        _idlePrev: [Circular],
        _idleStart: 1453475881306,
        _monotonicStartTime: 898918969,
        pipe: [Function],
        addListener: [Function: addListener],
        on: [Function: addListener],
        pause: [Function],
        resume: [Function],
        read: [Function],
        _consuming: true },
     _idlePrev: { _idleNext: [Circular], _idlePrev: [Object] },
     _idleStart: 1453475881568,
     _monotonicStartTime: 898919231,
     parser: 
      { _headers: [],
        _url: '',
        onHeaders: [Function: parserOnHeaders],
        onHeadersComplete: [Function: parserOnHeadersComplete],
        onBody: [Function: parserOnBody],
        onMessageComplete: [Function: parserOnMessageComplete],
        socket: [Circular],
        incoming: [Circular],
        maxHeaderPairs: 2000,
        onIncoming: [Function] },
     ondata: [Function],
     _paused: false,
     _httpMessage: 
      { domain: null,
        _events: [Object],
        _maxListeners: 10,
        output: [],
        outputEncodings: [],
        writable: true,
        _last: false,
        chunkedEncoding: false,
        shouldKeepAlive: true,
        useChunkedEncodingByDefault: true,
        sendDate: true,
        _headerSent: false,
        _header: '',
        _hasBody: true,
        _trailer: '',
        finished: false,
        _hangupClose: false,
        socket: [Circular],
        connection: [Circular],
        _headers: [Object],
        _headerNames: [Object],
        write: [Function],
        end: [Function] } },
  connection: 
   { _connecting: false,
     _handle: 
      { fd: 32,
        writeQueueSize: 0,
        owner: [Circular],
        onread: [Function: onread],
        reading: true },
     _readableState: 
      { highWaterMark: 16384,
        buffer: [],
        length: 0,
        pipes: null,
        pipesCount: 0,
        flowing: false,
        ended: false,
        endEmitted: false,
        reading: true,
        calledRead: true,
        sync: false,
        needReadable: true,
        emittedReadable: false,
        readableListening: false,
        objectMode: false,
        defaultEncoding: 'utf8',
        ranOut: false,
        awaitDrain: 0,
        readingMore: false,
        decoder: null,
        encoding: null },
     readable: true,
     domain: null,
     _events: 
      { end: [Object],
        finish: [Function: onSocketFinish],
        _socketEnd: [Function: onSocketEnd],
        drain: [Object],
        timeout: [Function],
        error: [Function],
        close: [Object] },
     _maxListeners: 10,
     _writableState: 
      { highWaterMark: 16384,
        objectMode: false,
        needDrain: false,
        ending: false,
        ended: false,
        finished: false,
        decodeStrings: false,
        defaultEncoding: 'utf8',
        length: 0,
        writing: false,
        sync: false,
        bufferProcessing: false,
        onwrite: [Function],
        writecb: null,
        writelen: 0,
        buffer: [],
        errorEmitted: false },
     writable: true,
     allowHalfOpen: true,
     onend: [Function],
     destroyed: false,
     bytesRead: 4987,
     _bytesDispatched: 1231,
     _pendingData: null,
     _pendingEncoding: '',
     server: 
      { domain: null,
        _events: [Object],
        _maxListeners: 10,
        _connections: 6,
        connections: [Getter/Setter],
        _handle: [Object],
        _usingSlaves: false,
        _slaves: [],
        allowHalfOpen: true,
        httpAllowHalfOpen: false,
        timeout: 5000,
        _connectionKey: '4:0.0.0.0:8080' },
     _idleTimeout: 120000,
     _idleNext: 
      { _connecting: false,
        _handle: [Object],
        _readableState: [Object],
        readable: true,
        domain: null,
        _events: [Object],
        _maxListeners: 10,
        _writableState: [Object],
        writable: true,
        allowHalfOpen: false,
        onend: null,
        destroyed: false,
        bytesRead: 14384,
        _bytesDispatched: 1798,
        _pendingData: null,
        _pendingEncoding: '',
        _idleTimeout: 30000,
        _idleNext: [Object],
        _idlePrev: [Circular],
        _idleStart: 1453475881306,
        _monotonicStartTime: 898918969,
        pipe: [Function],
        addListener: [Function: addListener],
        on: [Function: addListener],
        pause: [Function],
        resume: [Function],
        read: [Function],
        _consuming: true },
     _idlePrev: { _idleNext: [Circular], _idlePrev: [Object] },
     _idleStart: 1453475881568,
     _monotonicStartTime: 898919231,
     parser: 
      { _headers: [],
        _url: '',
        onHeaders: [Function: parserOnHeaders],
        onHeadersComplete: [Function: parserOnHeadersComplete],
        onBody: [Function: parserOnBody],
        onMessageComplete: [Function: parserOnMessageComplete],
        socket: [Circular],
        incoming: [Circular],
        maxHeaderPairs: 2000,
        onIncoming: [Function] },
     ondata: [Function],
     _paused: false,
     _httpMessage: 
      { domain: null,
        _events: [Object],
        _maxListeners: 10,
        output: [],
        outputEncodings: [],
        writable: true,
        _last: false,
        chunkedEncoding: false,
        shouldKeepAlive: true,
        useChunkedEncodingByDefault: true,
        sendDate: true,
        _headerSent: false,
        _header: '',
        _hasBody: true,
        _trailer: '',
        finished: false,
        _hangupClose: false,
        socket: [Circular],
        connection: [Circular],
        _headers: [Object],
        _headerNames: [Object],
        write: [Function],
        end: [Function] } },
  httpVersion: '1.1',
  complete: false,
  headers: 
   { host: '/*...omitted...*/',
     'user-agent': 'eBayNioHttpClient 1.0',
     'content-length': '2840',
     'cache-control': 'max-age=86400',
     connection: 'keep-alive',
     'content-type': 'text/xml;charset=utf-8',
     soapaction: '"http://developer.ebay.com/notification/AskSellerQuestion"',
     via: '1.1 phx7b02c-718782 (squid)',
     'x-forwarded-for': '/*...omitted...*/',
     'x-forwarded-proto': 'http',
     'x-mod-region': '/*...omitted...*/',
     'accept-encoding': 'gzip' },
  trailers: {},
  _pendings: [],
  _pendingIndex: 0,
  url: '/api/ebay//*...omitted...*/',
  method: 'POST',
  statusCode: null,
  client: 
   { _connecting: false,
     _handle: 
      { fd: 32,
        writeQueueSize: 0,
        owner: [Circular],
        onread: [Function: onread],
        reading: true },
     _readableState: 
      { highWaterMark: 16384,
        buffer: [],
        length: 0,
        pipes: null,
        pipesCount: 0,
        flowing: false,
        ended: false,
        endEmitted: false,
        reading: true,
        calledRead: true,
        sync: false,
        needReadable: true,
        emittedReadable: false,
        readableListening: false,
        objectMode: false,
        defaultEncoding: 'utf8',
        ranOut: false,
        awaitDrain: 0,
        readingMore: false,
        decoder: null,
        encoding: null },
     readable: true,
     domain: null,
     _events: 
      { end: [Object],
        finish: [Function: onSocketFinish],
        _socketEnd: [Function: onSocketEnd],
        drain: [Object],
        timeout: [Function],
        error: [Function],
        close: [Object] },
     _maxListeners: 10,
     _writableState: 
      { highWaterMark: 16384,
        objectMode: false,
        needDrain: false,
        ending: false,
        ended: false,
        finished: false,
        decodeStrings: false,
        defaultEncoding: 'utf8',
        length: 0,
        writing: false,
        sync: false,
        bufferProcessing: false,
        onwrite: [Function],
        writecb: null,
        writelen: 0,
        buffer: [],
        errorEmitted: false },
     writable: true,
     allowHalfOpen: true,
     onend: [Function],
     destroyed: false,
     bytesRead: 4987,
     _bytesDispatched: 1231,
     _pendingData: null,
     _pendingEncoding: '',
     server: 
      { domain: null,
        _events: [Object],
        _maxListeners: 10,
        _connections: 6,
        connections: [Getter/Setter],
        _handle: [Object],
        _usingSlaves: false,
        _slaves: [],
        allowHalfOpen: true,
        httpAllowHalfOpen: false,
        timeout: 5000,
        _connectionKey: '4:0.0.0.0:8080' },
     _idleTimeout: 120000,
     _idleNext: 
      { _connecting: false,
        _handle: [Object],
        _readableState: [Object],
        readable: true,
        domain: null,
        _events: [Object],
        _maxListeners: 10,
        _writableState: [Object],
        writable: true,
        allowHalfOpen: false,
        onend: null,
        destroyed: false,
        bytesRead: 14384,
        _bytesDispatched: 1798,
        _pendingData: null,
        _pendingEncoding: '',
        _idleTimeout: 30000,
        _idleNext: [Object],
        _idlePrev: [Circular],
        _idleStart: 1453475881306,
        _monotonicStartTime: 898918969,
        pipe: [Function],
        addListener: [Function: addListener],
        on: [Function: addListener],
        pause: [Function],
        resume: [Function],
        read: [Function],
        _consuming: true },
     _idlePrev: { _idleNext: [Circular], _idlePrev: [Object] },
     _idleStart: 1453475881568,
     _monotonicStartTime: 898919231,
     parser: 
      { _headers: [],
        _url: '',
        onHeaders: [Function: parserOnHeaders],
        onHeadersComplete: [Function: parserOnHeadersComplete],
        onBody: [Function: parserOnBody],
        onMessageComplete: [Function: parserOnMessageComplete],
        socket: [Circular],
        incoming: [Circular],
        maxHeaderPairs: 2000,
        onIncoming: [Function] },
     ondata: [Function],
     _paused: false,
     _httpMessage: 
      { domain: null,
        _events: [Object],
        _maxListeners: 10,
        output: [],
        outputEncodings: [],
        writable: true,
        _last: false,
        chunkedEncoding: false,
        shouldKeepAlive: true,
        useChunkedEncodingByDefault: true,
        sendDate: true,
        _headerSent: false,
        _header: '',
        _hasBody: true,
        _trailer: '',
        finished: false,
        _hangupClose: false,
        socket: [Circular],
        connection: [Circular],
        _headers: [Object],
        _headerNames: [Object],
        write: [Function],
        end: [Function] } },
  _consuming: false,
  _dumped: false,
  httpVersionMajor: 1,
  httpVersionMinor: 1,
  upgrade: false,
  originalUrl: '/api/ebay//*...omitted...*/',
  _parsedUrl: 
   { protocol: null,
     slashes: null,
     auth: null,
     host: null,
     port: null,
     hostname: null,
     hash: null,
     search: null,
     query: null,
     pathname: '/api/ebay//*...omitted...*/',
     path: '/api/ebay//*...omitted...*/',
     href: '/api/ebay//*...omitted...*/' },
  query: {},
  body: {} }

响应上有一个名为 'data' 的事件,只要响应有数据就会触发该事件。我们可以很快得到响应状态代码,但数据可能需要一些时间才能加载。

试试这个:

response.on('data', function handleResponse(data) {
  console.log("data from the response");
  console.log(data);
});