反应 - 404 未找到
React - 404 not found
我在从 React 向我的端点 /send-email
发出请求时遇到问题。我已 flask-mail
配置为进行异步调用。
这是前端发出请求的方式:
emailClient(event, index){
let {clientCount} = this.state;
var headers = {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': true,
Authorization: `Bearer ${window.localStorage.authToken}`
}
const {userId} = this.props
const client = this.state.clients[index];
const data = {
client: client
};
const url = `${process.env.REACT_APP_WEB_SERVICE_URL}/send-email/${userId}`;
axios.post(url, data, {headers: headers})
.then((res) => {
this.setState({
clientCount: clientCount +1
});
console.log(data);
})
.catch((err) => {
});
};
渲染:
render() {
const orders = this.state.clients;
const { clients, youtube_urls, loadedVideosCount, currentPlayingIndex } = this.state;
return (
<div>
<h1 className="title is-1">Jukebox</h1>
{this.state.isLoading}
{
clients.map((client, index) => {
/*
Obtain preview from state.previews for current artist index
*/
const audio = youtube_urls[index]
/*
Render current client data, and corresponding audio url
*/
return(
<div key={index}>
<ul>
<li><font color="#C86428">Client: </font><strong><font color="#6f4e37"> { client.name } </font></strong></li>
<li><font color="#C86428">Phone: </font><strong><font color="#6f4e37"> { client.phone } </font></strong></li>
<li><font color="#C86428">Email: </font><strong><font color="#6f4e37"> { client.mail } </font></strong></li>
<li><font color="#C86428">Artist: </font><strong><font color="#6f4e37"> { client.tracks[0].artist } </font></strong></li>
<li><font color="#C86428">Track: </font><strong><font color="#6f4e37"> { client.tracks[0].title } </font></strong></li>
<ReactPlayer
url={ audio }
controls
width='50'
height='150'
onLoaded={() =>
this.setState(currentState => ({
loadedVideosCount: loadedVideosCount + 1,
currentPlayingIndex:
loadedVideosCount + 1 === youtube_urls.length ? 0 : -1,
}))
}
onStart={() => this.emailClient(index)} //<--------
onEnded={() =>
this.setState(currentState => ({
currentPlayingIndex: currentPlayingIndex + 1,
}))
}
playing={index === currentPlayingIndex}
/>
</ul></div>
)
})
}
</div>
)
};
};
export default Jukebox;
我收到以下错误:
POST http://localhost/send-email/1 404 (Not Found)
端点:
@task_bp.route('/send-email/<user_id>', methods=['GET','POST'])
def send_email(user_id):
try:
#business logic
send_async_email.delay()
return jsonify(response_object), 200
except (exc.IntegrityError, ValueError):
db.session.rollback()
return jsonify(response_object), 400
nginx
反向代理配置:
location /send-email {
proxy_pass http://web:5000;
proxy_redirect default;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}
邮件服务所依赖的 'web' 和 'client' 服务是使用 docker-compose
:
构建的
services:
web:
build:
context: ./services/web
dockerfile: Dockerfile-dev
volumes:
- './services/web:/usr/src/app'
ports:
- 5001:5000
environment:
- FLASK_ENV=development
- APP_SETTINGS=project.config.DevelopmentConfig
- DATABASE_URL=postgres://postgres:postgres@web-db:5432/web_dev
- DATABASE_TEST_URL=postgres://postgres:postgres@web-db:5432/web_test
- SECRET_KEY=my_precious
- GOOGLE_APPLICATION_CREDENTIALS=/usr/src/app/project/api/resources/youtube/urls/z.json
depends_on:
- web-db
- redis
client:
build:
context: ./services/client
dockerfile: Dockerfile-dev
volumes:
- './services/client:/usr/src/app'
- '/usr/src/app/node_modules'
ports:
- 3000:3000
environment:
- NODE_ENV=development
- REACT_APP_WEB_SERVICE_URL=${REACT_APP_WEB_SERVICE_URL}
depends_on:
- web
每次构建它们时,我都会:
$export REACT_APP_WEB_SERVICE_URL=http://localhost
有什么问题吗?
NOTE:
如果我 post 直接使用 POSTMAN 到端点 http://localhost:5001/send-email/1
,就可以了。
在客户端 localhost:
之后添加端口 5001
为我修复了它:
const url = `${process.env.REACT_APP_WEB_SERVICE_URL}:5001/send-email/${userId}`;
控制台:
XHR finished loading: OPTIONS "http://localhost:5001/send-email/1".
我仍然不明白为什么,因为所有其他几十个端点分配 5001
,但它是固定的。任何澄清原因的答案都将被授予赏金。
在您的 Nginx 前端网络服务器配置中,您设置了一个反向代理以将请求传递给 /send-email
到主机名 web
侦听端口 5000
的网络应用程序服务器。
location /send-email {
proxy_pass http://web:5000;
这意味着您可以直接向 /send-email/1
请求。
您在问题中指出,OPTIONS
请求在您的浏览器中执行并获得 404
响应,而 POST
是预期的结果。
这是因为使用 axios 客户端执行的请求是预检请求。
对于preflight requests,浏览器首先向路径发出OPTIONS
请求,以确定请求是否可以安全发送。
许多特征决定了预检请求,其中之一是 Content-Type
header 的值不同于 application/x-www-form-urlencoded | multipart/form-data | text/plain
响应 OPTIONS
请求以确认 POST
请求是安全的,必须有 Access-Control-Allow-*
headers 这样说明。比如你的POST
请求中的请求headers是:
Content-Type
Authorization
为了从服务器确认 POST
请求是安全的,OPTIONS
请求的响应 headers 必须是
Access-Control-Allow-Origin: http://localhost
Access-Control-Allow-Methods: HEAD, OPTIONS, GET, POST
Access-Control-Allow-Headers: Authorization, Content-Type, Access-Control-Allow-Origin
Access-Control-Max-Age: 86400
您可以在 Nginx 配置中处理此预检响应。例如
location /send-email {
# ...
if ($request_method = OPTIONS) {
add_header 'Access-Control-Allow-Origin' 'http://localhost';
add_header 'Access-Control-Allow-Methods' 'HEAD, OPTIONS, GET, POST';
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, Access-Control-Allow-Origin';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Max-Age' 86400;
return 204;
}
}
或者,您可以在视图函数中处理 OPTIONS
请求
from functools import wraps
def cors(f):
'''Handle preflight OPTIONS request'''
@wraps
def wrapper(*args, **kwargs):
if request.method != 'OPTIONS':
return make_response(f(*args, **kwargs))
response = current_app.make_default_options_response()
access_control_headers = {
'Access-Control-Allow-Origin': 'http://localhost',
'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, POST',
'Access-Control-Max-Age': '86400',
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Allow-Headers': 'Authorization, Content-Type, Access-Control-Allow-Origin',
}
response.headers.extend(access_control_headers)
return response
return wrapper
@cors
@task_bp.route('/send-email/<user_id>', methods=['GET','POST'])
def send_email(user_id):
# ...
我在从 React 向我的端点 /send-email
发出请求时遇到问题。我已 flask-mail
配置为进行异步调用。
这是前端发出请求的方式:
emailClient(event, index){
let {clientCount} = this.state;
var headers = {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': true,
Authorization: `Bearer ${window.localStorage.authToken}`
}
const {userId} = this.props
const client = this.state.clients[index];
const data = {
client: client
};
const url = `${process.env.REACT_APP_WEB_SERVICE_URL}/send-email/${userId}`;
axios.post(url, data, {headers: headers})
.then((res) => {
this.setState({
clientCount: clientCount +1
});
console.log(data);
})
.catch((err) => {
});
};
渲染:
render() {
const orders = this.state.clients;
const { clients, youtube_urls, loadedVideosCount, currentPlayingIndex } = this.state;
return (
<div>
<h1 className="title is-1">Jukebox</h1>
{this.state.isLoading}
{
clients.map((client, index) => {
/*
Obtain preview from state.previews for current artist index
*/
const audio = youtube_urls[index]
/*
Render current client data, and corresponding audio url
*/
return(
<div key={index}>
<ul>
<li><font color="#C86428">Client: </font><strong><font color="#6f4e37"> { client.name } </font></strong></li>
<li><font color="#C86428">Phone: </font><strong><font color="#6f4e37"> { client.phone } </font></strong></li>
<li><font color="#C86428">Email: </font><strong><font color="#6f4e37"> { client.mail } </font></strong></li>
<li><font color="#C86428">Artist: </font><strong><font color="#6f4e37"> { client.tracks[0].artist } </font></strong></li>
<li><font color="#C86428">Track: </font><strong><font color="#6f4e37"> { client.tracks[0].title } </font></strong></li>
<ReactPlayer
url={ audio }
controls
width='50'
height='150'
onLoaded={() =>
this.setState(currentState => ({
loadedVideosCount: loadedVideosCount + 1,
currentPlayingIndex:
loadedVideosCount + 1 === youtube_urls.length ? 0 : -1,
}))
}
onStart={() => this.emailClient(index)} //<--------
onEnded={() =>
this.setState(currentState => ({
currentPlayingIndex: currentPlayingIndex + 1,
}))
}
playing={index === currentPlayingIndex}
/>
</ul></div>
)
})
}
</div>
)
};
};
export default Jukebox;
我收到以下错误:
POST http://localhost/send-email/1 404 (Not Found)
端点:
@task_bp.route('/send-email/<user_id>', methods=['GET','POST'])
def send_email(user_id):
try:
#business logic
send_async_email.delay()
return jsonify(response_object), 200
except (exc.IntegrityError, ValueError):
db.session.rollback()
return jsonify(response_object), 400
nginx
反向代理配置:
location /send-email {
proxy_pass http://web:5000;
proxy_redirect default;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}
邮件服务所依赖的 'web' 和 'client' 服务是使用 docker-compose
:
services:
web:
build:
context: ./services/web
dockerfile: Dockerfile-dev
volumes:
- './services/web:/usr/src/app'
ports:
- 5001:5000
environment:
- FLASK_ENV=development
- APP_SETTINGS=project.config.DevelopmentConfig
- DATABASE_URL=postgres://postgres:postgres@web-db:5432/web_dev
- DATABASE_TEST_URL=postgres://postgres:postgres@web-db:5432/web_test
- SECRET_KEY=my_precious
- GOOGLE_APPLICATION_CREDENTIALS=/usr/src/app/project/api/resources/youtube/urls/z.json
depends_on:
- web-db
- redis
client:
build:
context: ./services/client
dockerfile: Dockerfile-dev
volumes:
- './services/client:/usr/src/app'
- '/usr/src/app/node_modules'
ports:
- 3000:3000
environment:
- NODE_ENV=development
- REACT_APP_WEB_SERVICE_URL=${REACT_APP_WEB_SERVICE_URL}
depends_on:
- web
每次构建它们时,我都会:
$export REACT_APP_WEB_SERVICE_URL=http://localhost
有什么问题吗?
NOTE:
如果我 post 直接使用 POSTMAN 到端点 http://localhost:5001/send-email/1
,就可以了。
在客户端 localhost:
之后添加端口 5001
为我修复了它:
const url = `${process.env.REACT_APP_WEB_SERVICE_URL}:5001/send-email/${userId}`;
控制台:
XHR finished loading: OPTIONS "http://localhost:5001/send-email/1".
我仍然不明白为什么,因为所有其他几十个端点分配 5001
,但它是固定的。任何澄清原因的答案都将被授予赏金。
在您的 Nginx 前端网络服务器配置中,您设置了一个反向代理以将请求传递给 /send-email
到主机名 web
侦听端口 5000
的网络应用程序服务器。
location /send-email {
proxy_pass http://web:5000;
这意味着您可以直接向 /send-email/1
请求。
您在问题中指出,OPTIONS
请求在您的浏览器中执行并获得 404
响应,而 POST
是预期的结果。
这是因为使用 axios 客户端执行的请求是预检请求。
对于preflight requests,浏览器首先向路径发出OPTIONS
请求,以确定请求是否可以安全发送。
许多特征决定了预检请求,其中之一是 Content-Type
header 的值不同于 application/x-www-form-urlencoded | multipart/form-data | text/plain
响应 OPTIONS
请求以确认 POST
请求是安全的,必须有 Access-Control-Allow-*
headers 这样说明。比如你的POST
请求中的请求headers是:
Content-Type
Authorization
为了从服务器确认 POST
请求是安全的,OPTIONS
请求的响应 headers 必须是
Access-Control-Allow-Origin: http://localhost
Access-Control-Allow-Methods: HEAD, OPTIONS, GET, POST
Access-Control-Allow-Headers: Authorization, Content-Type, Access-Control-Allow-Origin
Access-Control-Max-Age: 86400
您可以在 Nginx 配置中处理此预检响应。例如
location /send-email {
# ...
if ($request_method = OPTIONS) {
add_header 'Access-Control-Allow-Origin' 'http://localhost';
add_header 'Access-Control-Allow-Methods' 'HEAD, OPTIONS, GET, POST';
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, Access-Control-Allow-Origin';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Max-Age' 86400;
return 204;
}
}
或者,您可以在视图函数中处理 OPTIONS
请求
from functools import wraps
def cors(f):
'''Handle preflight OPTIONS request'''
@wraps
def wrapper(*args, **kwargs):
if request.method != 'OPTIONS':
return make_response(f(*args, **kwargs))
response = current_app.make_default_options_response()
access_control_headers = {
'Access-Control-Allow-Origin': 'http://localhost',
'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, POST',
'Access-Control-Max-Age': '86400',
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Allow-Headers': 'Authorization, Content-Type, Access-Control-Allow-Origin',
}
response.headers.extend(access_control_headers)
return response
return wrapper
@cors
@task_bp.route('/send-email/<user_id>', methods=['GET','POST'])
def send_email(user_id):
# ...