React 开发服务器不代理表单提交
Posted
技术标签:
【中文标题】React 开发服务器不代理表单提交【英文标题】:React dev server does not proxy form submissions 【发布时间】: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/"
【问题讨论】:
我也遇到了这个问题,不幸的是我仍然没有设法弄清楚大声笑。但是文档确实说text/html
不能在代理工作的请求标头中。 create-react-app.dev/docs/proxying-api-requests-in-development
【参考方案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.authenticated
将isAuthenticated
设置为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,并让浏览器进行重定向。很高兴知道一种让服务器执行重定向的方法(不添加路由)。以上是关于React 开发服务器不代理表单提交的主要内容,如果未能解决你的问题,请参考以下文章