在Express中使用中间件时,第三方API调用失败

时间:2018-12-24 20:49:34

标签: node.js express

我正在使用我在后端设置的路由来更新可以从客户端启动的数据库:

router.use('/update-database', (req, res) => {
  dbUpdate()
  .then(() => res.json({
    success: true,
    error: null,
  }));
});

我的dbUpdate函数涉及对第三方的许多API调用,并且在花费时间最长的第三方上它总是会失败。我将日志放入dbUpdate函数中,并在控制台中看到类似以下的内容:

first step completed
second step completed
third, fourth and fifth steps started concurrently
third step completed
fifth step completed
Error: Request failed with status code 408(sometimes 504 too)
GET /api/update-database - - ms - -

在我的浏览器控制台中,我看到了

GET http://localhost:3000/api/update-database net::ERR_EMPTY_RESPONSE
Uncaught (in promise) TypeError: Failed to fetch

如果我在服务器中手动执行dbUpdate函数,它将顺利进行。我尝试增加请求和响应时间,但是没有运气。有人可以照亮吗?

这是我的后端设置的入口点:

import express from 'express';
import logger from 'morgan';
import mongoose from 'mongoose';
import getItemsFromType from './optimizely';
import Project from './models/project';
import Campaign from './models/campaign';
import Experiment from './models/experiment';
import KnownPage from './models/knownPage';
import Page from './models/page';

require('dotenv').config();

const app = express();
const router = express.Router();
const API_PORT = process.env.API_PORT || 3001;

const projectIds = [];

app.use(logger('dev'));
app.use('/api', router);

mongoose.connect(process.env.DB_URI, { useNewUrlParser: true });
mongoose.Promise = global.Promise;
const db = mongoose.connection;
db.on('error', console.error.bind(console, 'MongoDB connection error: '));

const init = () => {
  console.log('Clearing all models');
  return Promise.all([
    Project.deleteMany({}), Campaign.deleteMany({}), Experiment.deleteMany({}), KnownPage.deleteMany({}), Page.deleteMany({})]);
};

// update collections
const updateProjectCollection = () => getItemsFromType('project')
  .then(data => Project.insertMany(data.map((e) => {
    projectIds.push(e.id);
    return {
      id: e.id,
      name: e.name,
      status: e.status,
      created: e.created,
      last_modified: e.last_modified,
    };
  })))
  .then(() => {
    console.log('project collection update completed');
    return projectIds;
  })
  .catch(err => console.log(err));

const updateCampaignCollection = () => Promise.all(projectIds.map(prjId => getItemsFromType('campaign', prjId)
  .then(data => Campaign.insertMany(data.map(e => ({
    id: e.id,
    project_id: e.project_id,
    name: e.name,
    page_ids: e.page_ids,
    status: e.status,
    created: e.created,
    last_modified: e.last_modified,
  }))))
  .then((docs) => {
    for (let i = 0; i < docs.length; i++) {
      if (docs[i].page_ids) {
        return Promise.all((docs[i].page_ids).map(pageId => new KnownPage({ id: pageId }).save()));
      }
      return new KnownPage({ id: -1 }).save();
    }
  })
  .catch(err => console.log(err))))
  .then(() => { console.log('campaign collection update completed'); });

const updateExperimentCollection = () => Promise.all(projectIds.map(prjId => getItemsFromType('experiment', prjId)
  .then(data => Experiment.insertMany(data.map(e => ({
    id: e.id,
    project_id: e.project_id,
    name: e.name,
    page_ids: e.page_ids,
    status: e.status,
    created: e.created,
    last_modified: e.last_modified,
  }))))
  .then((docs) => {
    for (let i = 0; i < docs.length; i++) {
      if (docs[i].page_ids) {
        return Promise.all((docs[i].page_ids).map(pageId => new KnownPage({ id: pageId }).save()));
      }
      return new KnownPage({ id: -1 }).save();
    }
  })
  .catch(err => console.log(err))))
  .then(() => { console.log('experiment collection update completed'); });

const updatePageCollection = () => Promise.all(projectIds.map(prjId => getItemsFromType('page', prjId)
  .then(data => Page.insertMany(data.map(e => ({
    id: e.id,
    project_id: e.project_id,
    name: e.name,
    archived: e.archived,
    created: e.created,
    last_modified: e.last_modified,
  }))))))
  .then(() => { console.log('page collection update completed'); })
  .catch(err => console.log(err));

const dbUpdate = () => init()
  .then(() => updateProjectCollection())
  .then(() => {
    console.log('project ids are available to use');
    return Promise.all([
      updateCampaignCollection(),
      updateExperimentCollection(),
      updatePageCollection(),
    ]);
  });

router.get('/', (req, res) => {
  res.json({ message: 'Welcome!' });
});

router.use('/update-database', (req, res) => {
  dbUpdate()
    .then(() => res.json({
      success: true,
      error: null,
    }));
});

app.listen(API_PORT, () => console.log(`Listening on port ${API_PORT}`));

这是在optimize.js中定义getItemsFromType的方式:

import axios from 'axios';

require('dotenv').config();

const perPage = 100;

const getItemsFromType = (type, prjId = 0, pagination = 1, arr = []) => {
  const url = (type === 'project') ? `https://api.optimizely.com/v2/projects?per_page=${perPage}&page=${pagination}` : `https://api.optimizely.com/v2/${type}s?project_id=${prjId}&per_page=${perPage}&page=${pagination}`;

  return axios.get(url, {
    headers: {
      Authorization: `Bearer 2:${process.env.OPTLY_API_KEY}`,
    },
  })
    .then((data) => {
      arr = arr.concat(data.data);
      if (data.data.length < 100) { return arr; }
      return getItemsFromType(type, prjId, ++pagination, arr);
    })
    .catch((err) => {
      console.log(`in getAllProjects: ${err}`);
    });
};

export default getItemsFromType;

0 个答案:

没有答案