Не работают GET/POST запросы на express сервер в React приложении именно в деплое на heroku
В режиме разработки все работает, есть proxy, axios тащу data на фронтенд, все связано, но вот при deploy приложения на heroku и подобные ему хостинги(netlify, vercel, surge) сервер будто не отдает api и в консоли, во вкладке preview любого из запросов вылезает You need to enable JavaScript to run this app.
Структура проекта
-songbird
--node_modules
--public
--src
---index.js
---components
----App.js
----Остальные компоненты
--.env
--.gitignore
--package.json
--package-lock.json
--Procfile
--server.js
Файлы
package.js
{
"name": "songbird",
"version": "0.1.0",
"private": true,
"main": "server.js",
"dependencies": {
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
"axios": "^0.20.0",
"babel-register": "^6.26.0",
"bcrypt": "^5.0.0",
"body-parser": "^1.19.0",
"bootstrap": "^4.5.2",
"concurrently": "^5.3.0",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"express-favicon": "^2.0.1",
"gh-pages": "^3.1.0",
"git": "^0.1.5",
"heroku-cli": "^7.0.9",
"koa": "^2.13.0",
"koa-bodyparser": "^4.3.0",
"koa-json": "^2.0.2",
"koa-proxy": "^1.0.0-alpha.3",
"koa-router": "^9.4.0",
"node": "^12.13.0",
"node-fetch": "^2.6.1",
"nodemon": "^2.0.4",
"react": "^16.13.1",
"react-awesome-modal": "^2.0.5",
"react-bootstrap": "^1.3.0",
"react-dom": "^16.13.1",
"react-google-login": "^5.1.21",
"react-router": "^5.2.0",
"react-router-dom": "^5.2.0",
"react-scripts": "3.4.3"
},
"scripts": {
"client": "react-scripts start",
"start": "nodemon server.js",
"dev": "concurrently \"npm run start\" \"npm run client\"",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"predeploy": "npm run build",
"deploy": "gh-pages -d build",
"heroku-postbuild": "NPM_CONFIG_PRODUCTION=false npm install && npm run build"
},
"proxy": "http://localhost:4000",
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
Procfile
web: npm run start
.env
GENERATE_SOURCEMAP=false
.gitignore
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.env
package-lock.json.*
server.js
const express = require('express')
const app = express()
const path = require('path');
const favicon = require('express-favicon')
const PORT = process.env.PORT || 4000
const bodyParser = require('body-parser')
const bcrypt = require('bcrypt')
const prefix = 'https://cors-anywhere.herokuapp.com/'
require('dotenv').config()
let users = []
app.use(bodyParser.urlencoded({ extended: true }))
app.use(bodyParser.json())
if (process.env.NODE_ENV === 'production') {
app.use(express.static(path.join(__dirname, 'build')));
app.get('*', function(req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
}
app.get('/czech', (req, res) => {
let data = [
{
name: 'Slava',
age: 15
}
]
return res.send(data)
})
app.get('/forest-birds', (req, res) => {
const api = [
{
url: `https://www.xeno-canto.org/api/2/recordings?query=kea`,
audio: 'https://www.xeno-canto.org/sounds/uploaded/BLMSIUFTFU/XC405529-180129_0139_kea.mp3',
first: 'Попугай',
second: 'Kea',
third: 'Сова',
img_url: 'https://www.flickr.com/services/rest/?
method=flickr.photos.search&api_key=78d959bd0249442712c00a6addb8513c&tag_mode=all&extras=url_m&format=json&nojsoncallback=1&tags=kea',
latin: 'Nestor notabilis',
right: 'Kea',
img: 'https://live.staticflickr.com/65535/50339726833_93bb650815.jpg'
},
{
url: `https://www.xeno-canto.org/api/2/recordings?query=tanager`,
audio: 'https://www.xeno-canto.org/sounds/uploaded/SHMWBKDDGP/XC539351-Rhodinocichla%20rosea.mp3',
first: 'Танагра-кео',
second: 'Трясогуска',
third: 'Ворон',
img_url: 'https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key=78d959bd0249442712c00a6addb8513c&tag_mode=all&extras=url_m&format=json&nojsoncallback=1&tags=tanager',
latin: 'Tangara fastuosa',
right: 'Танагра-кео',
img: 'https://live.staticflickr.com/65535/50354305497_74979b8906.jpg'
}
]
return res.send(api)
})
app.get('/tits-birds', (req, res)=> {
const api = [
{
url: `https://www.xeno-canto.org/api/2/recordings?query=tit`,
audio: 'https://www.xeno-canto.org/sounds/uploaded/CDTGHVBGZP/Titicaca%20Grebe2009-11-4-4t.mp3',
first: 'Синица',
second: 'Короткокрылая поганка',
third: 'Ястреб',
img_url: 'https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key=78d959bd0249442712c00a6addb8513c&tag_mode=all&extras=url_m&format=json&nojsoncallback=1&tags=tit',
latin: 'Phacellodomus striaticeps',
right: 'Короткокрылая поганка',
img: 'https://live.staticflickr.com/65535/50354919956_7fb7a43504.jpg'
},
{
url: `https://www.xeno-canto.org/api/2/recordings?query=titmouse`,
audio: 'https://www.xeno-canto.org/sounds/uploaded/FFNYJFDJXV/XC563113-170702BridledTitmouseCornville.mp3',
first: 'Американский гренадёр',
second: 'Трясогуска',
third: 'Ворон',
img_url: 'https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key=78d959bd0249442712c00a6addb8513c&tag_mode=all&extras=url_m&format=json&nojsoncallback=1&tags=titmouse',
latin: 'Psaltriparus minimus',
right: 'Американский гренадёр',
img: 'https://live.staticflickr.com/65535/50353792046_982b6e3c8c.jpg'
}
]
return res.send(api)
})
app.get('/ocean-birds', (req, res) => {
const api = [
{
url: `https://www.xeno-canto.org/api/2/recordings?query=albatross`,
audio: 'https://www.xeno-canto.org/sounds/uploaded/FNIOJOZADD/XC209430-LaysanAlbatross_oahu_010115_billclack2.mp3',
first: 'Фригат',
second: 'Oak',
third: 'Темноспинный альбатрос',
img_url: 'https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key=78d959bd0249442712c00a6addb8513c&tag_mode=all&extras=url_m&format=json&nojsoncallback=1&tags=albatross',
latin: 'Diomedeidae',
right: 'Oak',
img: 'https://live.staticflickr.com/65535/50348114416_aba462aefe.jpg'
},
{
url: `https://www.xeno-canto.org/api/2/recordings?query=petrel`,
audio: 'https://www.xeno-canto.org/sounds/uploaded/YAELHUNFDF/XC401263-wilson%27s%20storm%20petrel%20%282%29.MP3',
first: 'Качурка Вильсона',
second: 'Кака',
third: 'Тупик',
img_url: 'https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key=78d959bd0249442712c00a6addb8513c&tag_mode=all&extras=url_m&format=json&nojsoncallback=1&tags=petrel',
latin: 'Procellariidae',
right: 'Качурка Вильсона',
img: 'https://live.staticflickr.com/65535/50354453447_8bbe9de640.jpg'
}
]
return res.send(api)
})
app.post('/signup', async (req, res) => {
try {
let salt = await bcrypt.genSalt()
let data = req.body.data
data.password = await bcrypt.hash(data.password, salt)
console.log(data)
users.push(data)
return res.send(data)
} catch (e) {
console.log(e)
}
})
app.post('/signin', async (req, res) => {
const user = users.find(el => el.name = req.body.data.name)
try {
if (await bcrypt.compare(req.body.data.password, user.password)) {
console.log('Equal')
return res.send('Great')
}
} catch (e) {
console.log(e)
}
})
app.listen(PORT, () => console.log(`Server has started at ${PORT} port`))
App.js
import React, {useEffect, useState} from 'react'
import './App.css'
import axios from 'axios'
import MainBird from './MainBird'
import {Route} from 'react-router-dom'
const App = React.memo(function App() {
const [data1, setData1] = useState([])
const [data2, setData2] = useState([])
const [data3, setData3] = useState([])
useEffect(async () => {
const dt1 = await axios.get('/forest-birds')
setData1(dt1.data)
}, [])
useEffect(async () => {
const dt1 = await axios.get('/tits-birds')
setData2(dt1.data)
}, [])
useEffect(async () => {
const dt1 = await axios.get('/ocean-birds')
setData3(dt1.data)
}, [])
return (
<div className="App">
{data1 !== undefined && data2 !== undefined && data3 !== undefined ?
<>
<Route path='/' component={() => <MainBird data={data1} />} exact/>
<Route path='/tits' component={() => <MainBird data={data2} />} exact/>
<Route path='/ocean' component={() => <MainBird data={data3} />} exact/>
</>
: null}
</div>
);
})
export default App;