【问题标题】:React dev server does not proxy form submissionsReact 开发服务器不代理表单提交
【发布时间】:2019-02-26 03:25:49
【问题描述】:

我使用 create-react-app 创建了一个 react 应用,并且我的代理在使用 axios 发送请求时工作正常。

我想做一个“正常”的表单提交(没有使用 axios 的 onsubmit 功能)。我想这样做是因为我的 Node.js 服务器会重定向我(axios 不会将用户/浏览器发送到重定向,只会通过请求来跟踪它,这是我不想要的)

当我的表单被提交时,它只是转到我的开发服务器 localhost:3000/login 而不是我的节点服务器 localhost:8080/login 我相信这是因为

开发服务器只会尝试将其 Accept 标头中没有 text/html 的请求发送到代理。

source

我看到我的表单提交中的请求确实有那个标题,这可能是它忽略它的原因。

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8

有没有办法进行代理到我的节点服务器而不是开发服务器的“正常”表单提交?

我认为这将在生产中工作,因为它都在同一台服务器上运行,所以我在想为什么它会在生产中工作,但在开发中不可能?

这是我的表单的样子

render() {
    return <div>
        <Form action='/login' className="some-class">
            <Button type="submit" className="some-class">
                Log In
            </Button>
        </Form>
    </div>
}

这是我的代理配置在 package.json 中的样子

"proxy": "https://localhost:8080/"

【问题讨论】:

标签: reactjs forms webpack-dev-server


【解决方案1】:

由于您正在转向前端路由,我建议您集成 react-router(我更喜欢 v3.0.4 而不是 v4.x)仅用于处理前端路由和 express(或任何您想要的using) 仅用于处理后端 API 请求。

以下示例仅用于路由演示目的,不应按原样使用。

首先,在客户端的package.json中设置代理(这样做的主要好处是避免使用CORS):

"proxy": {
  "/api/*": {
    "target": "http://localhost:8080"
  }
}

我的客户 routes 将被设置为使 App 始终保持挂载并充当 children 路由的传递:

client/src/routes/index.js

import React from 'react';
import { Route } from 'react-router';
import App from '../components/App';
import Dashboard from '../components/Dashboard';
import NotFound from '../components/NotFound';

export default (
  <Route path="/" component={App}>
    <Route path="dashboard" component={Dashboard} />
    <Route path="*" component={NotFound} />
  </Route>
);

在我的App.js 中,我可以使用isAuthenticated 状态检查:

client/src/components/App.js

import React, { Component, Fragment } from 'react';
import { browserHistory } from 'react-router';
import LoginForm from './LoginForm'

export default class App extends Component {
    state = { isAuthenticated: false };

    componentDidMount = () => !this.state.isAuthenticated && browserHistory.push('/')

    componentDidUpdate = (prevProps, prevState) => !this.state.isAuthenticated && browserHistory.push('/')

    authenticated = () => this.setState({ isAuthenticated: true }, () => browserHistory.push('/dashboard'))

    render = () => (
       !this.state.isAuthenticated
          ? <LoginForm authenticated={this.authenticated} />
          : <Fragment>
             {this.props.children}
            </Fragment>
    )
}

然后,在LoginForm 组件中,我可以在AJAX 请求成功时通过this.props.authenticatedisAuthenticated 设置为true,然后重定向到dashboard

client/src/components/LoginForm.js

import React, {Component} from 'react';
import axios from 'axios';

export default class LoginForm extends Component {
  state = {
    login: "",
    password: ""
  }

  handleChange = e => this.setState({ [e.target.name]: e.target.value })

  handleSubmit = e => {
    e.preventDefault();

    const { login, password } = this.state;
    if (!login || !password ) return;

    axios.post('/api/login', { login, password })
      .then(() => this.props.authenticated())
      .catch(err => console.error(err.toString()))
  }

  render = () => (
    <form onSubmit={this.handleSubmit} className="some-class">
      <input 
        name="login"
        type="text" 
        value={this.state.login} 
        placeholder="Username" 
        onChange={this.handleChange}
      />
      <input 
        name="password"
        type="password" 
        value={this.state.password} 
        placeholder="Password" 
        onChange={this.handleChange}
      />
      <button type="submit" className="some-class">
        Log In
      </button>
    </form>
  )
}

那么快递服务器routes 会寻找POST 请求:

server/routes/auth.js

const { login } = require('../controllers/auth.js');

app.post('/login', login);

然后,我可以在我的 express 控制器中通过 passport 对用户进行身份验证(如果用户未能通过身份验证,那么它将被捕获在 handleSubmit 内的 AJAX .catch() 中):

服务器/控制器/auth.js

exports.login = (req, res, done) => passport.authenticate('local-login', (err, user) => {
                  if (err || !user) { res.status(404).json({ err: "Authentication failed." }); done(); }

                  res.status(201).send(null);
                })(req, res, done)

【讨论】:

  • 感谢马特的回答,我用反应研究了路由,但这似乎对我想要的东西来说有点过分了。我只需要提交 1 份表单即可正常运行,无需其他任何操作。相反,我让服务器发回带有位置标头的 204,并让浏览器进行重定向。很高兴知道一种让服务器执行重定向的方法(不添加路由)。
猜你喜欢
  • 1970-01-01
  • 2016-11-10
  • 2017-10-25
  • 1970-01-01
  • 1970-01-01
  • 2021-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多