После развертывания приложения React в Heroku из dev env Fetch-запросы прерываются - все GET-запросы возвращают index.html - остальные 404 - PullRequest
0 голосов
/ 15 сентября 2018

Я только что развернул свой проект Create-React-App в Heroku. В процессе разработки я использовал два отдельных порта - локальный HTML + JS обслуживался из React WebpackDevServer с использованием сценариев npm/yarn start на порте 3000. Backend был Express + NodeJS, работающий на порту 3001. Я настроил все запросы на выборку использовать mode:'cors' и предоставил обработчик API, чтобы избежать ошибок CORS. Типичный запрос на выборку будет выглядеть так:

При развертывании в Heroku все теперь хранится в одном Dyno, а приложение Express обслуживает файлы React (bundle + index.html), а также обрабатывает логику внутренней маршрутизации.

Вот пример моего кода API:

const express = require('express');
const mongoose = require('mongoose');
const path = require('path');
const bodyParser = require('body-parser');
const config = require('./models/config');
require('dotenv').config()
const app = express();
const server = require('http').createServer(app);

const storeItems= require('./controllers/storeItems')
const authorize= require('./controllers/authorize')
const router = express.Router(); 

mongoose.Promise = global.Promise; 
mongoose.connect(`mongodb://${process.env.MLABS_USER}:${process.env.MLABS_PW}@ds113000.mlab.com:13000/omninova`, { useMongoClient: true });

app.use(bodyParser.json());

// Middleware to handle CORS in development:

app.use('/*', function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, x-access-token, x-user-pathway, x-mongo-key, X-Requested-With, Content-Type, Accept");
  res.header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
  next();
});

app.use(express.static(path.join(__dirname, 'client/build')));

router.route('/api/storeItem/')
    .get(storeItems.getAllStoreItems)
    .post(storeItems.createNewStoreItem);

router.route('/authorize')
    .post(authorize.login);

// Catch-All Handler should send Client index.html for any request that does not match previous routes

router.route('*')
    .get((req, res) => {
        res.sendFile(path.join(__dirname+'/client/build/index.html'));
    });

app.use('/', router);

server.listen(config.port);
module.exports = app;

У меня есть некоторые проблемы, ВСЕ мои запросы на получение возвращают мою страницу index.html со следующей ошибкой: Unexpected token < in JSON at position 0

У меня есть следующий запрос на получение:

    return fetch(`/api/storeItem`, {
        headers:{
            'Content-Type': 'application/json',
        },
        method: 'GET',
        mode: 'no-cors',
    })
    .then(response => response.ok ? response.json() : Promise.reject(response))
    .then(json => {
        dispatch(receiveItems(json))
    })
    .catch(err => console.log(err))

Это сбой, потому что вместо запуска промежуточного программного обеспечения Express, которое должно быть запущено storeItems.getAllStoreItems на бэкэнде, он проходит этот маршрут и запускает обработчик catch-all, который я использую для обслуживания index.html при первоначальном запросе:

router.route('*')
    .get((req, res) => {
        res.sendFile(path.join(__dirname+'/client/build/index.html'));
    });

Другая путаница заключается в том, что следующий запрос извлечения возвращает 404, хотя маршрут /authorize ожидает запрос POST в коде API:

export function attemptLogIn(credentials) {
    return dispatch => {
        return fetch('/authorize', {
        headers:{
            'Content-Type': 'application/json'
        },
        method: 'POST',
        mode: 'no-cors'
        body: JSON.stringify(credentials)
        })
        .then(response => response.ok ? response.json() : Promise.reject(response.statusText))
        .then(json => {
            dispatch(routeUserAfterLogin(json.accountType))
        })
        .catch(err => dispatch(authFail(err.message)))
    }
} 

Любая помощь с этим будет принята с благодарностью. Я предполагаю, что я делаю что-то не так с Express Router, поскольку маршрут авторизации просто не выбирается.

Я следовал инструкциям в этом сообщении, чтобы помочь мне настроить мой новый проект: https://daveceddia.com/deploy-react-express-app-heroku/

Редактировать: это код извлечения из моей ветки разработки. Это успешно регистрирует пользователя, не возвращая 404. Однако я вообще не использую универсальный обработчик или промежуточное программное обеспечение express.static:

return fetch('http://localhost:3001/authorize', {
    headers:{
        'Content-Type': 'application/json'
    },
    method: 'POST',
    mode: 'cors', 
    body: JSON.stringify(credentials)
})

Редактировать: я просто изменил URL, который указывает на bundle.js на app.use(express.static(path.join(__dirname, '/../../build'))); Я не уверен, каким образом я даже отправлял HTML раньше, так как это фактическое местоположение файлов сборки. Я не уверен, как они были найдены раньше.

Edit2: нашел мою проблему, я оставил в стартовом скрипте для моего проекта React (который фактически запустил сервер разработки webpack ...)

Ответы [ 2 ]

0 голосов
/ 15 сентября 2018

Ваш сервер отправляет не ответ json, а HTML-контент.Измените ответ на res.text () и зарегистрируйте его.https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

router.route('*')
    .get((req, res) => {
        res.sendFile(path.join(__dirname+'/client/build/index.html'));
    });
0 голосов
/ 15 сентября 2018

Для первой части

Ошибка: неожиданный токен <в JSON в позиции 0 </p>

Я предполагаю, что без сервера dev, express не может обработатьпакет загружается автоматически.Итак, когда ваш index.html достигает /path/to/bundle.js, он попадает под маршрутный символ («*»), который возвращает сам HTML.Ваш браузер затем пытается проанализировать его как JS, но не может, так как это HTML, поэтому возникает ошибка.

Я бы попробовал что-то вроде:

app.get("path/to/bundle.js", (req, res) => {
  res.sendFile("path/to/bundle.js");
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...