javascript - 无法在heroku上的node+express网站的index.js中创建新路线

标签 javascript node.js reactjs express

我有以下index.js 文件:

const express = require('express');
const path = require('path');
const generatePassword = require('password-generator');
const fetch = require('node-fetch');
const FetchTweets = require('fetch-tweets');
const request = require('request');

const TW_URL = "http://1.1/search/tweets.json"  // Twitter search URL
const SEN_URL =  "http://www.sentiment140.com/api/bulkClassifyJson" // URL of sentiment analysis

var TW_KEYS = {
  consumer_key: process.env.TW_KEY,
  consumer_secret: process.env.TW_SECRET
}

const app = express();
const fetchTweets = new FetchTweets(TW_KEYS);

// Serve static files from the React app
app.use(express.static(path.join(__dirname, 'client/build')));

// Put all API endpoints under '/api'
app.get('/api/passwords', (req, res) => {
  const count = 5;

  // Generate some passwords
  const passwords = Array.from(Array(count).keys()).map(i =>
    generatePassword(12, false)
  )

  // Return them as json
  res.json(passwords);

  console.log(`Sent ${count} passwords`);
});

// The "catchall" handler: for any request that doesn't
// match one above, send back React's index.html file.
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname+'/client/build/index.html'));
});

const port = process.env.PORT || 5000;
app.listen(port);

console.log(`Password generator listening on ${port}`);

以及我的 React App.js:

import React, { Component } from 'react';
import './App.css';

class App extends Component {
  // Initialize state
  state = { passwords: [] }

  // Fetch passwords after first mount
  componentDidMount() {
    this.getPasswords();
  }

  getPasswords = () => {
    // Get the passwords and store them in state
    fetch('/api/passwords')
      .then(res => res.json())
      .then(passwords => this.setState({ passwords }));
  }

  render() {
    const { passwords } = this.state;

    return (
      <div className="App">
        {/* Render the passwords if we have them */}
        {passwords.length ? (
          <div>
            <h1>5 Passwords.</h1>
            <ul className="passwords">
              {/*
                Generally it's bad to use "index" as a key.
                It's ok for this example because there will always
                be the same number of passwords, and they never
                change positions in the array.
              */}
              {passwords.map((password, index) =>
                <li key={index}>
                  {password}
                </li>
              )}
            </ul>
            <button
              className="more"
              onClick={this.getPasswords}>
              Get More
            </button>
          </div>
        ) : (
          // Render a helpful message otherwise
          <div>
            <h1>No passwords :(</h1>
            <button
              className="more"
              onClick={this.getPasswords}>
              Try Again?
            </button>
          </div>
        )}
      </div>
    );
  }
}

export default App;

效果非常好。现在,我想添加一条新路线,因此我将 index.js 更改为:

const express = require('express');
const path = require('path');
const generatePassword = require('password-generator');
const fetch = require('node-fetch');
const FetchTweets = require('fetch-tweets');
const request = require('request');

const TW_URL = "http://1.1/search/tweets.json"  // Twitter search URL
const SEN_URL =  "http://www.sentiment140.com/api/bulkClassifyJson" // URL of sentiment analysis

var TW_KEYS = {
  consumer_key: process.env.TW_KEY,
  consumer_secret: process.env.TW_SECRET
}

const app = express();
const fetchTweets = new FetchTweets(TW_KEYS);

// Serve static files from the React app
app.use(express.static(path.join(__dirname, 'client/build')));

app.get('/api/sentiment', async (req, res) => {
  console.log("matched /api/sentiment pattern")
  const options = {
    q : req.query.q,
    lang : "en",
    count : 100,
  }
  try{
    fetchTweets.byTopic(options, async function(results){
      const tweets = {"data": results.map(function(tweet){
        return {"text": tweet.body, "query": options.q}
      })}
      var body = JSON.stringify(tweets)

      // get sentiments
      const sentiments = await fetch(SEN_URL, {method: "POST", body: body})
      const json = await sentiments.json()
      const data = json.data

      //console.log(data)

      // calculate percentages
      const response = {positive: undefined, neutral: undefined, negative: undefined}
      var numPos = 0
      var numNeu = 0
      var numNeg = 0
      //console.log(response)
      data.forEach(function(tweet){
        switch(tweet.polarity){
          case 4:
            numPos += 1
            break
          case 2:
            numNeu += 1
            break
          case 0:
            numNeg += 1
            break
        }
      })
      const tot = numPos + numNeu + numNeg
      response.positive = numPos/tot
      response.neutral = numNeu/tot
      response.negative = numNeg/tot
      // send response
      res.send(response)
    })
  }catch (error){
    console.log(error)
  }
})

// Put all API endpoints under '/api'
app.get('/api/passwords', (req, res) => {
  const count = 5;

  // Generate some passwords
  const passwords = Array.from(Array(count).keys()).map(i =>
    generatePassword(12, false)
  )

  // Return them as json
  res.json(passwords);

  console.log(`Sent ${count} passwords`);
});

// The "catchall" handler: for any request that doesn't
// match one above, send back React's index.html file.
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname+'/client/build/index.html'));
});

const port = process.env.PORT || 5000;
app.listen(port);

console.log(`Password generator listening on ${port}`);

注意新路由/api/sentiments。我还在 App.js 中调用了这个新的 URL 路径:

import React, { Component } from 'react';
import './App.css';

class App extends Component {
  // Initialize state
  state = { passwords: [] }

  // Fetch passwords after first mount
  componentDidMount() {
    this.getPasswords();
    this.getSentiments();
  }

  getSentiments = () => {
    fetch("/api/sentiment?q=hello")
      .then(res => console.log(res))

  }

getSentiments 函数是 API 对新路由的调用。但这行不通。这是浏览器控制台消息:

GET https://glacial-refuge-37109.herokuapp.com/api/sentiment?q=hello 503 (Service Unavailable)
i.getSentiments @ App.js:15
value @ App.js:11
commitLifeCycles @ react-dom.production.min.js:159
C @ react-dom.production.min.js:185
w @ react-dom.production.min.js:182
g @ react-dom.production.min.js:181
v @ react-dom.production.min.js:181
h @ react-dom.production.min.js:180
s @ react-dom.production.min.js:179
t @ react-dom.production.min.js:190
updateContainer @ react-dom.production.min.js:191
nn.render @ react-dom.production.min.js:228
(anonymous) @ react-dom.production.min.js:242
unbatchedUpdates @ react-dom.production.min.js:188
ln @ react-dom.production.min.js:242
render @ react-dom.production.min.js:244
(anonymous) @ index.js:7
t @ bootstrap 8940ebd453621d06336e:19
(anonymous) @ main.1f99a125.js:526
t @ bootstrap 8940ebd453621d06336e:19
(anonymous) @ bootstrap 8940ebd453621d06336e:62
(anonymous) @ bootstrap 8940ebd453621d06336e:62
App.js:16 Response {type: "basic", url: "https://glacial-refuge-37109.herokuapp.com/api/sentiment?q=hello", redirected: false, status: 503, ok: false, …}

看起来我收到了 503,服务不可用。为什么?我怎样才能做到这一点?顺便说一句,这在本地运行良好。

最佳答案

在 catch block 中添加 res.send

app.get('/api/sentiment', async (req, res) => {
  console.log("matched /api/sentiment pattern")
  const options = {
    q : req.query.q,
    lang : "en",
    count : 100,
  }
  try{
    fetchTweets.byTopic(options, async function(results){
      const tweets = {"data": results.map(function(tweet){
        return {"text": tweet.body, "query": options.q}
      })}
      var body = JSON.stringify(tweets)

      // get sentiments
      const sentiments = await fetch(SEN_URL, {method: "POST", body: body})
      const json = await sentiments.json()
      const data = json.data

      //console.log(data)

      // calculate percentages
      const response = {positive: undefined, neutral: undefined, negative: undefined}
      var numPos = 0
      var numNeu = 0
      var numNeg = 0
      //console.log(response)
      data.forEach(function(tweet){
        switch(tweet.polarity){
          case 4:
            numPos += 1
            break
          case 2:
            numNeu += 1
            break
          case 0:
            numNeg += 1
            break
        }
      })
      const tot = numPos + numNeu + numNeg
      response.positive = numPos/tot
      response.neutral = numNeu/tot
      response.negative = numNeg/tot
      // send response
      res.send(response)
    })
  }catch (error){
    console.log(error)
    res.send(error)
  }
})

您的函数失败,并且由于您没有发送响应,因此永远挂起

关于javascript - 无法在heroku上的node+express网站的index.js中创建新路线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49923977/

相关文章:

node.js - TypeError : db. 集合不是函数

node.js - Socket.io 无法在带有 Nodejs 的 aws 上工作

reactjs - react-bootstrap Accordion 未加载

javascript - Sharepoint 2013。使用 JavaScript 的多值查找字段

javascript - d3.js 在调整大小事件中缩放圆环图

javascript - 通过许多对象优化我的搜索查询

node.js - 测试 Webhooks 的正确方法是什么?

javascript - 如何在同一个 react 应用程序中将 redux 和 graphql 与 apollo 客户端一起使用?

javascript - 当我尝试在 onsubmit 函数中调用函数时,函数未定义

javascript - DOJO 声明中可选的 className 参数有什么用?