Невозможно получить Nuxt. js, Express и сторонний API для совместной работы. - PullRequest
0 голосов
/ 15 января 2020

Я уже несколько недель пытаюсь получить Nuxt. js + Express (используя create-nuxt-app) для работы со сторонним API. Неважно, что я пытаюсь, ничего, абсолютно ничего, работает. Никакие операторы консоли с моей серверной стороны не запускаются, только операторы переднего плана. Кроме того, недавно я начал получать Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client, и я нигде в своем коде не устанавливаю заголовки.

Все, что я хочу сделать, - это принять пользовательский ввод, передать его на сервер, чтобы избежать проблем с CORS, получить данные из стороннего API, а затем отобразить их. Это просто. Это происходит все время в inte rnet, так почему я не могу заставить его работать?

Ниже приведены все файлы, вовлеченные в процесс, описанный выше.

pages / index . vue:

<template>
  <div class="container">
    <img src="@/assets/images/OscarPark.jpg" alt="Oscar in the park" title="I love the park!" />
    <br />
    <form>
      <label for="title">Book Title:</label>
      <input v-model="titleFromUser" type="text" name="title" class="title" />
      <button @click.prevent="submit" class="submit">Find a Book!</button>
    </form>
  </div>
</template>

<script>
import { mapState } from 'vuex';

export default {
  components: {},
  data() {
    return {
      titleFromUser: '',
    };
  },
  computed: mapState(['newTitles']),
  methods: {
    submit() {
      this.$store.dispatch('FETCH_BOOK_TITLES', this.titleFromUser);
      this.titleFromUser = '';
    },
  },
};
</script>

<style lang="scss">
.container {
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;

  img {
    transform: rotate(90deg); // this fixes a glitch that causes image to rotate needlessly
    padding-top: $underHeaderGap; // these 2 padding lines help to fix the placement of the image caused by the needless rotation
    padding-left: $underHeaderGap * 5;
    margin-bottom: $underHeaderGap * 5;
    height: $imgHeight;
  }
}
</style>

store / index. js:

import consola from 'consola';

export const state = () => ({
  newTitles: [],
});

export const mutations = {
  SET_NEW_TITLES(state, newTitles) {
    state.newTitles = newTitles;
  },
};

export const actions = {
  async FETCH_BOOK_TITLES({ commit }, titleFromUser) {
    try {
      consola.ready({
        message: `'FETCH_BOOK_TITLES': titleFromUser: ${titleFromUser}`,
        badge: true,
      });
      const { data } = await this.$axios.$post('/title', { titleFromUser });
      consola.ready({
        message: `data returned from api: ${data}`,
        badge: true,
      });
      commit('SET_NEW_TITLES', data);
    } catch (error) {
      consola.error({
        message: `FETCH_BOOK_TITLES: Something went wrong: ${error}`,
        badge: true,
      });
      throw new Error(error);
    }
  },
};

server / index. js:

const express = require('express');
const cors = require('cors');
const consola = require('consola');
const axios = require('axios');
const { Nuxt, Builder } = require('nuxt');
const app = express();
const jsonParser = express.json();

const titleRouter = require('../api/title/index');

// Import and Set Nuxt.js options
const config = require('../nuxt.config.js');
config.dev = process.env.NODE_ENV !== 'production';

async function start() {
  // Init Nuxt.js
  const nuxt = new Nuxt(config);

  const { host, port } = nuxt.options.server;

  // Give app ability to parse json
  app.use(jsonParser);

  // Give app ability to get past CORS issues
  app.use(cors());

  // Give nuxt middleware to express
  app.use(nuxt.render);

  // Build only in dev mode
  if (config.dev) {
    const builder = new Builder(nuxt);
    await builder.build();
  } else {
    await nuxt.ready();
  }

  app.use('/title', titleRouter);

  app.get('/title', (req, res) => {
    consola.ready({
      message: `res.json in title endpoint-server: ${res.json()}`,
      badge: true,
    });

    consola.ready({
      message: `req.json in title endpoint-server: ${req.json()}`,
      badge: true,
    });

    const recommendationsURL = `https://tastedive.com/api/similar?q=and+then+there+were+none&type=books&info=1&k=${process.env.TASTE_DIVE_API_KEY}`;

    axios
      .get(recommendationsURL, (req, res) => {
        consola.ready({
          message: `from server/index.js: ${res.json()}`,
          badge: true,
        });
      })
      .catch((error) => {
        consola.error({
          message: `error from axios server ${error} `,
          badge: true,
        });
      });
  });

  // Listen to the server
  app.listen(port, host, () => {
    consola.ready({
      message: `Server listening on http://${host}:${port}`,
      badge: true,
    });
  });
}

start();

api / title / index. js:

const consola = require('consola');
const express = require('express');
const app = express();
const titleRouter = express.Router();

titleRouter.use((req, res, next) => {
  Object.setPrototypeOf(req, app.request);
  Object.setPrototypeOf(res, app.response);
  req.res = res;
  res.req = req;
  next();
});

titleRouter.get('/title', (req, res) => {
  res
    .json()
    .then((data) => {
      consola.ready({
        message: `~api/title get title is ${data}`,
        badge: true,
      });
    })
    .catch((error) => {
      consola.error({
        message: `~api/title get Something went wrong: ${error}`,
        badge: true,
      });
      throw new Error(error);
    });
});

titleRouter.post('/title', (req, res) => {
  res
    .json()
    .then((data) => {
      consola.ready({
        message: `~api/title post title is ${data}`,
        badge: true,
      });
    })
    .catch((error) => {
      consola.error({
        message: `~api/title post Something went wrong: ${error}`,
        badge: true,
      });
      throw new Error(error);
    });
});

module.exports = titleRouter;

nuxt.config. js:

require('dotenv').config();

module.exports = {
  mode: 'universal',
  /*
   ** Headers of the page
   */
  head: {
    title: "Oscar's Book Recommendations",
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      {
        hid: 'description',
        name: 'description',
        content: process.env.npm_package_description || '',
      },
    ],
    link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }],
  },
  /*
   ** Customize the progress-bar color
   */
  loading: { color: '#fff' },
  /*
   ** Plugins to load before mounting the App
   */
  plugins: [],
  /*
   ** Nuxt.js dev-modules
   */
  buildModules: [
    // Doc: https://github.com/nuxt-community/eslint-module
    '@nuxtjs/eslint-module',
    '@nuxtjs/dotenv',
    '@nuxtjs/style-resources',
  ],
  /*
   ** Nuxt.js modules
   */
  modules: [
    // Doc: https://axios.nuxtjs.org/usage
    '@nuxtjs/axios',
    '@nuxtjs/pwa',
    '@nuxtjs/auth',
  ],
  /*
   ** Axios module configuration
   ** See https://axios.nuxtjs.org/options
   */
  axios: {
    https: true,
    baseURL: process.env.BASE_URL || 'http://localhost:3000',
  },
  /*
   ** Build configuration
   */
  build: {
    watch: ['api/title'],
    /*
     ** You can extend webpack config here
     */
    extend(config, ctx) {},
  },
  pageTransition: {
    name: 'fade',
    mode: 'out-in',
  },
  env: {
    TASTE_DIVE_API_KEY: process.env.TASTE_DIVE_API_KEY,
  },
  serverMiddleware: ['~api/title'],
  styleResources: {
    scss: ['~assets/styles/main.scss'],
  },
};

Кто-нибудь видит, кто я? Почему данные не передаются на сервер? Почему это говорит мне, что я не могу установить заголовки после их отправки, когда я не устанавливаю их где-нибудь в своем коде? Что не так с этим?

Я был бы очень признателен за любой вклад и помощь. Спасибо.

1 Ответ

0 голосов
/ 17 января 2020

Хорошо, так получилось, что у меня были server/index.js и nuxt.config.js с записью serverMiddleware. Себастьен Шопен, один из создателей Nuxt, натолкнулся на мой твит об этой проблеме и любезно указал, что я могу использовать либо файл server/index.js, либо serverMiddleware в моем nuxt.config.js, но НЕ оба, как я делал , Как человек, который впервые изучил Express, создавая серверные файлы, я легко вижу, как это может привести кого-то в замешательство.

В конце я остановился на способе использования Nuxt и использовал serverMiddleware по моему nuxt.config.js. Когда вы настраиваете проект Nuxt и выбираете интегрировать Express с самого начала, это предпочтительный способ использования Express, а не традиционные файлы сервера.

...