带有 axios 的 MERN 堆栈,响应对象返回 html 而不是 json [英] MERN stack with axios, response object returns html instead of json

查看:41
本文介绍了带有 axios 的 MERN 堆栈,响应对象返回 html 而不是 json的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我正在设置一个为期 5 天的天气预报 Web 应用程序,用于练习使用 MERN 堆栈与 API 交互.我正在使用 Axios.js 发送和响应请求;为了确保我的后端工作,我在开始与 API 通信之前首先开始构建它.但是,我在前端设置的按钮(它向我的服务器发送一个获取 json 数据的请求)总是返回一个响应对象,其中 response.data 的值为:

响应:<头><meta name="viewport" charset="UTF-8" content="width=device-width, initial-scale=1.0"><身体><div id="应用程序"></div><script src="./dist/bundle.js"></script>

代替

响应:你好!"

对于如下所示的 JavaScript:

{data: "你好!"}

我知道在发送和接收这些请求时我可能遗漏了一个步骤,但在对此进行研究后,我仍然不确定为什么我没有收到预期的结果.我的文件是这样设置的:

-weather_forcast-客户-src-组件(空)应用程序.jsx-上市-dist包.js索引.html-服务器-路线路由.js索引.js包.jsonwebpack.config.js

当前有代码的文件的内容是:

app.jsx

 import React, {Component} from 'react';导入 ReactDOM, {render} from 'react-dom';从 'axios' 导入 axios;//从 './daysOfWeek.jsx' 导入 daysOfWeek;类 App 扩展组件 {构造函数(){极好的();this.state = {}this.getData = this.getData.bind(this);}获取数据(){axios.get('/').then((响应) => {console.log("RESPONSE:", response.data);}).catch((错误) => {控制台日志(错误);})}使成为() {返回(<div><button onClick={this.getData}>Hello world</button>

)}}渲染(<App/>,document.getElementById('app'));

index.html

<头><meta name="viewport" charset="UTF-8" content="width=device-width, initial-scale=1.0"><身体><div id="应用程序"></div><script src="./dist/bundle.js"></script>

routes.js

let express = require('express');让路由器 = express.Router();router.get('/', (req, res) => {res.send({data:'你好!'});});module.exports = 路由器;

index.js

const express = require('express');const fs = require('fs');const path = require('path');const bodyParser = require('body-parser');const router = require('./routes/routes.js');const app = express();让端口 = 8000;app.use(bodyParser.urlencoded());app.use(bodyParser.json());app.use(express.static(path.join(__dirname, '../public')));app.use('/', 路由器);app.listen(port, () => {console.log(`express 正在监听端口 ${port}`);});

webpack.config.js

const path = require('path');const SRC_DIR = path.join(__dirname, '/client/src');const DIST_DIR = path.join(__dirname, '/public/dist');模块.出口 = {条目:`${SRC_DIR}/app.jsx`,输出: {文件名:'bundle.js',路径:DIST_DIR},模块: {规则: [{测试:/.jsx?/,包括:SRC_DIR,排除:/(node_modules|bower_components)/,利用: {loader: 'babel-loader',选项: {预设:['@babel/preset-env', '@babel/preset-react']}}}]}}

在我添加routes"文件夹并像这样设置我的 index.js 文件之前,同样的问题出现了:

const express = require('express');const fs = require('fs');const path = require('path');const bodyParser = require('body-parser');const router = require('./routes/routes.js');const app = express();让端口 = 8000;app.use(bodyParser.urlencoded());app.use(bodyParser.json());app.use(express.static(path.join(__dirname, '../public')));app.get('/', (req, res) => {res.send({data: "你好!"}););app.listen(port, () => {console.log(`express 正在监听端口 ${port}`);});

任何帮助将不胜感激!我似乎无法将我的 json 对象作为数据发送到前端,但我不确定我从这个设置中遗漏了什么.

解决方案

您得到的响应似乎表明开发服务器正在为您提供 React 应用程序(请注意以下行:<script src="./dist/bundle.js"></script>).

当您在不同的端口上同时运行两台服务器(例如 webpack 开发服务器和您的 express 应用程序)时,您有几个选项来处理它们.

1) CORS 使用完整地址向您的另一台服务器发出请求:

"http://localhost:8000/"

通常不建议这样做,除非您的服务器旨在与您的 React 应用程序完全分离并允许 CORS.鉴于服务器和客户端都存在于同一个存储库中,您似乎希望服务器也为您的 React 应用程序提供服务.

2) 代理请求

查看文档了解更多信息

Webpack 使您能够代理服务器请求.如果您在开发中使用不同的端口,这很有用,但您的服务器和 React 应用程序将在生产中放在一起.在您的 webpack.config.js 中,您可以执行以下操作:

webpack.config.js:

module.exports = {//先验规则模块: {//模块规则后跟逗号},开发服务器:{代理人: {"/api": "http://localhost:8000"}}}

在您的 express 服务器中,像这样在每个请求后附加api":/api/

路由:

app.use('/api', router);

app.jsx

getData() {axios.get('/api').then((响应) => {console.log("RESPONSE:", response.data);}).catch((错误) => {控制台日志(错误);})}

未来

最终,您可能希望 "/" 发送 React 应用程序,而不是使用纯静态方法.

在您的 express 应用中,您可以执行以下操作:

//提供 index.htmlconst path = require('path')app.get('*', (req, res) => {res.sendFile(path.resolve('<构建应用程序的路径 index.html>'))})

* 是任何先前未定义的请求",这意味着您应该所有 API 路由之后定义此.这样,除非发出 /api/.... 请求,否则您将响应应用程序.这样做的真正好处(在我看来)是所有与服务器路由不匹配的请求都在 React 应用程序中处理.

So I'm setting up a 5 day weather forecast web app for practice interacting with APIs using the MERN stack. I'm using Axios.js to send and respond to requests; to make sure I have my back-end working, I started building that out first before starting to communicate with the API. However, the button I have set up on the front-end (which sends a get request to my server for json data) always returns a response object with response.data having the value of:

RESPONSE: <!doctype html>
<html>
<head>
    <meta name="viewport" charset="UTF-8" content="width=device-width, initial-scale=1.0">
</head>
<body>
    <div id="app"></div>
    <script src="./dist/bundle.js"></script>
</body>
</html>

instead of

RESPONSE: "hello there!"

for a JavaScript that looks like:

{data: "hello there!"}

I know I'm probably missing a step when sending and receiving these requests, but after doing research into this I'm still not sure why I'm not receiving the expected result. My files are set up like this:

-weather_forcast
  -client
    -src
      -components(empty)
      app.jsx
  -public
    -dist
      bundle.js
    index.html
  -server
    -routes
      routes.js
    index.js
  package.json
  webpack.config.js

The contents of the files that currently have code in them are:

app.jsx

    import React, {Component} from 'react';
    import ReactDOM, {render} from 'react-dom';
    import axios from 'axios';
    // import daysOfWeek from './daysOfWeek.jsx';

    class App extends Component {
      constructor() {
          super();
          this.state = {
          }
          this.getData = this.getData.bind(this);
      }

      getData() {
          axios.get('/')
          .then((response) => {
              console.log("RESPONSE:", response.data);
          })
          .catch((error) => {
              console.log(error);
          })
      }

      render() {
          return(
              <div>
                  <button onClick={this.getData}>Hello world</button>
              </div>
          )
      }
  }

  render(<App/>, document.getElementById('app'));

index.html

<!doctype html>
<html>
    <head>
        <meta name="viewport" charset="UTF-8" content="width=device-width, initial-scale=1.0">
    </head>
    <body>
        <div id="app"></div>
        <script src="./dist/bundle.js"></script>
    </body>
</html>

routes.js

let express = require('express');
let router = express.Router();

router.get('/', (req, res) => {
    res.send({data:'hello there!'});
});

module.exports = router;

index.js

const express = require('express');
const fs = require('fs');
const path = require('path');
const bodyParser = require('body-parser');
const router = require('./routes/routes.js');
const app = express();
let port = 8000;

app.use(bodyParser.urlencoded());
app.use(bodyParser.json());
app.use(express.static(path.join(__dirname, '../public')));

app.use('/', router);

app.listen(port, () => {
  console.log(`express is listening on port ${port}`);
});

webpack.config.js

const path = require('path');
const SRC_DIR = path.join(__dirname, '/client/src');
const DIST_DIR = path.join(__dirname, '/public/dist');

module.exports = {
    entry: `${SRC_DIR}/app.jsx`,
    output: {
        filename: 'bundle.js',
        path: DIST_DIR
    },
    module: {
        rules: [
            {
                test: /.jsx?/,
                include: SRC_DIR,
                exclude: /(node_modules|bower_components)/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env', '@babel/preset-react']
                    }
                }
            }
        ]
    }
}

The same problem presents itself before I added the "routes" folder and had set up my index.js file like this:

const express = require('express');
const fs = require('fs');
const path = require('path');
const bodyParser = require('body-parser');
const router = require('./routes/routes.js');
const app = express();
let port = 8000;

app.use(bodyParser.urlencoded());
app.use(bodyParser.json());
app.use(express.static(path.join(__dirname, '../public')));

app.get('/', (req, res) => {
  res.send({data: "hello there!"});
);

app.listen(port, () => {
  console.log(`express is listening on port ${port}`);
});

Any help would be greatly appreciated! I can't seem to get my json object to the front end as data, but I'm not sure what I'm missing from this set up.

解决方案

The response you're getting seems to indicate the dev server is serving you the react application (note the line: <script src="./dist/bundle.js"></script>).

When you're running two servers simultaneously on different ports (ex webpack dev server and your express app), you have a few options to handle them.

1) CORS Make a request to your other server with its full address:

"http://localhost:8000/<path>"

This is generally not recommended unless your server is meant to be completely separate from your React application and allows CORS. Given that both server and client exist in the same repository, it seems that you're going to want your server to serve your React Application as well.

2) Proxying Requests

See Docs For More Info

Webpack gives you the ability to proxy server requests. This is useful if you're using a different port in development, but your server and react app will sit together in production. In your webpack.config.js you can do the following:

webpack.config.js:

module.exports = {
  // prior rules
  module: {
    // module rule followed by comma
  },
  devServer: {
    proxy: {
      "/api": "http://localhost:8000"
    }
  }
}

In your express server, append each request with 'api' like this: /api/<path>

routing:

app.use('/api', router);

app.jsx

getData() {
  axios.get('/api')
  .then((response) => {
    console.log("RESPONSE:", response.data);
  })
  .catch((error) => {
    console.log(error);
  })
}

In The Future

Eventually, you may want "/" to send the React application, instead of using a purely static approach.

In your express app, you can do something like this:

  // serve index.html
  const path = require('path')
  app.get('*', (req, res) => {
    res.sendFile(path.resolve('<PATH TO BUILT APP index.html>')) 
  })

The * is "any request not previously defined", meaning you should define this after all of your api routes. This way, you're react app is served unless a /api/.... request is made. The real advantage (in my opinion) of doing something like this is that all requests that do not match a server route are handled in the React application.

这篇关于带有 axios 的 MERN 堆栈,响应对象返回 html 而不是 json的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆