Ответы пользователя по тегу Express.js
  • Как деплоить проект написанный на reactjs?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Добрый день. Переносите бэкэнд на express на хостинг и запускаете. Так же переносите клиентский код на хостинг и запускаете.
    Если у вас сразу и клиент и сервер в одном проекте - то посмотрите, что у вас разное локально и на хостинге.

    google по поводу деплоя на heroku
    Ответ написан
    Комментировать
  • Как соединить front и back?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    dfv123 написал все верно, но добавлю: у вас больше нет шаблонов на handlebars. Максимум для index.html
    Ваш сервер, на все маршруты кроме тех, что вы напишете для API, должен отдавать index.html, где подключен "бандл" (общий файл скриптов js) и есть элемент, куда будет монтироваться приложение.

    Затем, вы создаете API: связка из нескольких маршрутов которые принимают запросы (GET/POST/PUT/DELETE) и отдают данные в виде JSON. Вы эти данные на клиенте считываете и отображаете.

    Роутинг внутри приложения (изменения урлов), тоже переезжает на клиент, и вы это будете делать, скорее всего с помощью react-router.
    Ответ написан
    1 комментарий
  • Как правильно загрузить файл с помощью multer?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Поскольку "запрос даже не вызывается", значит проблема в форме (не вижу в коде кнопки для отправки формы), далее нужно смотреть функцию handleSubmit и искать проблему там, если она есть.
    Ответ написан
  • Как реализовать грамотную проверку авторизации?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Вы используете react-router? Если да, то тут все просто:
    1) роуты создаются с помощью функции, таким образом вы можете прокинуть в роутинг store
    ...
    import configRoutes from '../../routes'
    ...
    render() {
      return (
        <Provider store={store}>
          <Router history={routerHistory}>
            {configRoutes(store)}
          </Router>
        </Provider>
      )
    }


    2) Далее в роутинге, устанавливаете на "защищенные" компоненты onEnter hook:
    ...
    <Route path='/secret-area' component={SecretAreaContainer} onEnter={_ensureAuthenticated}>
    ...


    3) сама функция, смотрит есть ли в store необходимые данные:
    export default function configRoutes(store) {
      function _ensureAuthenticated(nextState, replace, callback) {
        const { dispatch } = store
        const { session } = store.getState()
        const { currentUser } = session // данные по юзеру
        let nextUrl
    
        if (!currentUser && localStorage.getItem('token')) {
            dispatch(getCurrentAccount())
          }
        } else if (!localStorage.getItem('token')) {
          nextUrl = location.pathname + location.search.replace('?', '&')
          replace('/signin')
        }
    
        callback()
      }
    
      // здесь ваши роуты


    Ок, по роутам готово.

    Теперь, по переадресации:
    - на success в логине, делаете редирект куда угодно:
    export function signIn(email, password) {
      return (dispatch, getState) => {
    
        dispatch({
          type: USER_SIGN_IN_REQUEST,
        })
    
        const params = {
          email,
          password,
        }
    
        httpPost(`${API_ROOT_V1}/api/authenticate`, params)
          .then((data) => {
            saveParamsToLS(data) // здесь токен можно сохранить, например
            dispatch(push('/account')) // ваш РЕДИРЕКТ, используется push из react-router-redux (что необязательно)
          })
          .catch((error) => {
            console.warn(`Sign in error: ${JSON.stringify(error)}`) //eslint-disable-line no-console
            dispatch({
              type: USER_SIGN_IN_FAILURE,
              error: error,
            })
          })
      }
    }


    и остается кейс с прямым заходом: вы должны разрулить это опять же в onEnter хуке в роутере. Так как у вас есть store, и вам доступны все данные из него, включая store.dispatch метод, добить пример не составит труда.
    Ответ написан
    3 комментария
  • Как решить проблему перезагрузки страницы react-router?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Где-то отвечал на тостере, не могу найти вопрос, но ответ кроется здесь в главе, если у вас не грузится bundle, а скорее всего так и есть.
    Если нет - покажите ошибку в консоли браузера.
    Ответ написан
  • Какая разница в инструментах webpack?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    webpack-dev-server - средство для удобной разработки ваших одностраничных приложений от webpack (то есть, из "коробки")

    webpack-dev-middleware - собственно, middleware, который добавляет возможности вашему другому серверу (в случае тэга вопросов - написанному на node.js и фреймворке express). Что добавляет? Ну хотя бы, возможность hot-reload'a..

    Что и где использовать разницы нет. Как вам удобнее так и делайте. Либо просто webpack-dev-server, либо какой-то ваш "усложенный" сервер написанный на node.js + middleware webpack-dev-server. Под middlewar'ом можно понимать некий "усилитель", как уже было написано, например: усиливай мой "сервер" на "hot-reload"
    Ответ написан
    Комментировать
  • Как правильно настроить webpack-dev-server?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    1) либо не создан index.html на одном уровне с конфигом webpack
    2) либо нет роута по '/'

    p.s. + покажите console браузера, может там еще какая ошибка по делу будет.
    Ответ написан
  • Начальный шаблон express'a (что? где? куда?)?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Ищите поиском по статье, которую вы привели в примере:
    Здесь будут жить все ваши макеты и файлы представления Jade.

    То есть, ваши шаблоны нужно класть в директорию views. В статье используется jade, поэтому посмотрите как работает этот шаблонизатор. Шаблон главной страницы, доступной по урлу mysite.com
    demo-app/views/index.jade

    Далее, как запустить, снова ищем поиском в статье:
    Это код, который позволяет вам запускать npm start для приложения.

    => для запуска, нужно выполнить в терминале:
    node ./bin/www

    или можно
    npm start
    Ответ написан
    2 комментария
  • Что за сопостовления в express?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Это стадартный роутинг. Вы переходите по урлу, например mysite.com/abe или mysite.com/abcde , что сервер будет вам отдавать? Правильно, то что вы указали внутри "сопоставимого" роута, в случае этого примера, это ваш последний кейс:
    app.get('/ab(cd)?e', function(req, res) {
    res.send('ab(cd)?e'); // здесь может быть что-нибудь, например: покажи страницу с такой-то картинкой
    });
    Ответ написан
    1 комментарий
  • Nodejs/express + ES6 рекомендации?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    По первому пункту, ссылка от Антона в помощь.

    По второму вопросу: вы на node.js будете делать бэкэнд. Который будет являться API сервером, не более. Здесь придется поизучать что такое REST API. Следовательно, если вы будете писать фронтенд на react/redux, то кладете его в другую директорию, там уже свой package.json и т.д., так как ваш фронтенд и бэкэнд - это две разные вещи.
    Ответ написан
    Комментировать
  • Как работает роутинг в связке angular2 + express?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    А как вы вообще планируете использовать express ? MEAN стэк подразумевает, что ваш бэкэнд - это только REST API, если не ошибаюсь. Следовательно - у вас все запросы на youhost.com/api/, например, идут в express и там он разруливает роуты, а все остальные запросы идут в клиентское приложение и там разруливает ангуляр.
    Ответ написан
    Комментировать
  • Какие данные необходимо записывать в jwt (node.js + mongo)?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Логин класть в токен не нужно. В токене не должно быть "личной информации", а вот ObjectId уже можно. Это не подходит "под личную", так как по 5821d94dbb021a1360582da3 нельзя узнать что-то о пользователе, если у вас не своровали базу (могу ошибаться).

    Приведу на всякий случай полный код роута с выдачей токена, если вам не особо пригодится, так может кто поругает, так как в бэкэнде не силен. Код не на промисах, а на коллбэках (как в древние времена). Это плохо. С помощью промисов будет "более плоский" и удобный в поддержке код.

    const express = require('express')
    const router = express.Router()
    const User = require('../models/user')
    const v4 = require('node-uuid').v4
    const jwt = require('jsonwebtoken')
    
    router.post('/signup', (req, res, next) => {
    
      req.check('email', 'Please enter a valid email').len(1).isEmail()
      req.check('password', 'Please enter a password with a length between 4 and 34 digits').len(4, 34)
    
      const errors = req.validationErrors()
    
      if (errors) {
        return res.status(400).json({ errors })
      } else {
        User.hashPassword(req.body.password, (err, passwordHash) => {
          if (err) {
            return res.status(400).json({ error: err.message })
          }
    
          const user = new User({
            name: req.body.name,
            nickname: req.body.nickname,
            email: req.body.email,
            password: req.body.password,
          })
    
          user.passwordHash = passwordHash
          user.save((err, item) => {
            if (err) {
              return res.status(400).json({ error: err.message })
            }
            const payload = {
              _id: item._id,
              iss: 'http://localhost:3000',
              permissions: 'poll',
            }
            const options = {
              expiresIn: '7d',
              jwtid: v4(),
            }
            const secret = new Buffer(process.env.AUTH0_CLIENT_SECRET, 'base64')
            jwt.sign(payload, secret, options, (err, token) => {
              return res.json({ data: token })
            })
          })
        })
      }
    })
    
    router.post('/signin', (req, res, next) => {
    
      req.check('email', 'Please enter a valid email').len(1).isEmail()
      req.check('password', 'Please enter a password with a length between 4 and 34 digits').len(4, 34)
    
      const errors = req.validationErrors()
      const password = req.body.password
    
      if (errors) {
        return res.status(400).json({ errors })
      } else {
        User.findOne({ email: req.body.email }, (err, user) => {
          if (err) {
            return res.status(400).json({ error: err.message })
          }
          if (!user) {
            return res.status(400).json({ error: 'User not found' })
          }
          User.comparePasswordAndHash(password, user.passwordHash, (err, areEqual) => {
            if (err) {
              return res.status(400).json({ error: err.message })
            }
            if (!areEqual) {
              return res.status(400).json({ error: 'Wrong password' })
            }
            const payload = {
              _id: user._id,
              iss: 'http://localhost:3000',
              permissions: 'poll',
            }
            const options = {
              expiresIn: '7d',
              jwtid: v4(),
            }
            const secret = new Buffer(process.env.AUTH0_CLIENT_SECRET, 'base64')
            jwt.sign(payload, secret, options, (err, token) => {
              return res.json({ data: token })
            })
          })
        })
      }
    })
    
    module.exports = router;


    В дальнейшем, кусочек payload:
    const payload = {
              _id: item._id,
              iss: 'http://localhost:3000',
              permissions: 'poll',
            }

    можно "декодировать" прямо на клиенте, что очень удобно.
    Ответ написан
    Комментировать
  • Как правильно организовать авторизацию веб-сервиса на Express?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Как на счет jwt ?

    За! Удобно, нравится.

    Вкратце - шлете стандартные регистрационные данные, сервер выдает вам токен. Далее токен добавляете в заголовки запросов.

    В прицнипе, в гугле инфы хватает по вопросу. Сам сайт посмотрите (jwt.io), оттуда ссылка на пакет для node

    Скопирую сюда куски кода из своего api сервера, но скажу сразу - в node я не очень силен, если будут замечания от знающих - только рад. Так же angular кода не приведу, потому что клиентский код у меня на react.

    Здесь в файле используются callbacks, возможно есть варианты получше. В других роутах приложения я где-то через async поигрался, где-то через promise.

    Мой роутер auth

    const express = require('express')
    const router = express.Router()
    const User = require('../models/user')
    const v4 = require('node-uuid').v4
    const jwt = require('jsonwebtoken')
    
    router.post('/signup', (req, res, next) => {
    
      req.check('email', 'Please enter a valid email').len(1).isEmail()
      req.check('password', 'Please enter a password with a length between 4 and 34 digits').len(4, 34)
    
      const errors = req.validationErrors()
    
      if (errors) {
        return res.status(400).json({ errors })
      } else {
        User.hashPassword(req.body.password, (err, passwordHash) => {
          if (err) {
            return res.status(400).json({ error: err.message })
          }
    
          const user = new User({
            name: req.body.name,
            nickname: req.body.nickname,
            email: req.body.email,
            password: req.body.password,
          })
    
          user.passwordHash = passwordHash
          user.save((err, item) => {
            if (err) {
              return res.status(400).json({ error: err.message })
            }
            const payload = {
              _id: item._id,
              iss: 'http://localhost:3000',
              permissions: 'poll',
            }
            const options = {
              expiresIn: '7d',
              jwtid: v4(),
            }
            const secret = new Buffer(process.env.AUTH0_CLIENT_SECRET, 'base64')
            jwt.sign(payload, secret, options, (err, token) => {
              return res.json({ data: token })
            })
          })
        })
      }
    })
    
    router.post('/signin', (req, res, next) => {
    
      req.check('email', 'Please enter a valid email').len(1).isEmail()
      req.check('password', 'Please enter a password with a length between 4 and 34 digits').len(4, 34)
    
      const errors = req.validationErrors()
      const password = req.body.password
    
      if (errors) {
        return res.status(400).json({ errors })
      } else {
        User.findOne({ email: req.body.email }, (err, user) => {
          if (err) {
            return res.status(400).json({ error: err.message })
          }
          if (!user) {
            return res.status(400).json({ error: 'User not found' })
          }
          User.comparePasswordAndHash(password, user.passwordHash, (err, areEqual) => {
            if (err) {
              return res.status(400).json({ error: err.message })
            }
            if (!areEqual) {
              return res.status(400).json({ error: 'Wrong password' })
            }
            const payload = {
              _id: user._id,
              iss: 'http://localhost:3000',
              permissions: 'poll',
            }
            const options = {
              expiresIn: '7d',
              jwtid: v4(),
            }
            const secret = new Buffer(process.env.AUTH0_CLIENT_SECRET, 'base64')
            jwt.sign(payload, secret, options, (err, token) => {
              return res.json({ data: token })
            })
          })
        })
      }
    })
    
    module.exports = router;


    Модель user

    const mongoose = require('mongoose')
    const bcrypt = require('bcrypt')
    const Schema = mongoose.Schema
    let bcrypt_cost = 12
    
    const userSchema = new Schema({
      name: { type: String, required: true },
      email: { type: String, required: true },
      passwordHash: String,
    })
    
    userSchema.statics.hashPassword = (passwordRaw, cb) => {
      if (process.env.NODE_ENV === 'test') {
        bcrypt_cost = 1
      }
      bcrypt.hash(passwordRaw, bcrypt_cost, cb)
    }
    
    userSchema.statics.comparePasswordAndHash = (password, passwordHash, cb) => {
      bcrypt.compare(password, passwordHash, cb)
    }
    
    const User = mongoose.model('User', userSchema)
    
    module.exports = User


    В коде роутера есть AUTHO_CLIENT - так как я изначально брал реализацию от AUTH0, кстати, может понравится? У них удобно все... Но для себя в целях обучения переписал на свою. (какая-то ссылка у них про angular cookies vs token)

    Мне нравится, что некоторую информацию я могу взять прямо из токена (например, уровень доступа - в моем примере - poll)
    Ответ написан
  • Почему query получает не корректное значение?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    req.params.query
    Ответ написан
    Комментировать
  • Какой модуль/midelware для загрузки изображений на сервер node.js/express выбрать?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    Есть универсальный совет: когда выбираете модули, смотрите github проекта
    - когда было последнее обновление?
    - сколько issues не закрытых (и мельком, какие они)
    - сколько звезд

    Допустим модуль обновляется, пулреквесты автор принимает и публикует, критических issues мельком не видно. Тогда уже можно смотреть api модуля. Если нравится - берем и пробуем использовать. Если работает и делает что нужно - оставляем.
    Ответ написан
    Комментировать
  • Express не грузит bundel.js React-а, что не так?

    maxfarseer
    @maxfarseer
    https://maxpfrontend.ru, обучаю реакту и компании
    У вас скорее всего указан неверный путь до файла. Подробнее здесь (весь раздел прочитайте, он короткий).
    Ответ написан
    1 комментарий