Flask中redirect(url_for())无法实现页面跳转的问题排查
问题描述
提交表单后,服务器返回日志:
> 127.0.0.1 - - [02/Dec/2022 10:37:53] "POST /create-artist HTTP/1.1" 302 - > 127.0.0.1 - - [02/Dec/2022 10:37:53] "GET /artists-list HTTP/1.1" 200 -
浏览器收到响应,但URL停留在http://localhost:3000/create-artist,未发生跳转。已查阅5个相关问题,未找到匹配情况。
Python后端代码
from flask import Flask, render_template, url_for, redirect, request, abort from flask_sqlalchemy import SQLAlchemy import os, sys db = SQLAlchemy() app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = URI db.init_app(app) ########################################################## #################### CONTROLLERS ######################### ########################################################## # --------------------------------------------- # ----------------- ARTISTS ------------------- # --------------------------------------------- @app.route('/artists-list') def artists_list(): return render_template('artists.html', data='test') @app.route('/create-artist', methods = ["GET", "POST"]) def create_artist(): error = False if request.method == "POST": try: artist = Artist( name = request.get_json()['name'], city = request.get_json()['city'], state = request.get_json()['state'], phone = request.get_json()['phone'], genres = request.get_json()['genres'], ) # db.session.add(artist) # db.session.commit() print(artist) except: error = True # db.session.rollback() print(sys.exc_info()) # finally: # db.session.close() if not error: return redirect(url_for('artists_list')) else: abort(500) return render_template('form/create-artist.html') # --------------- END ARTISTS ------------------ @app.route("/") def index(): return render_template('home.html') ########################################################## ###################### MODELS ############################ ########################################################## class Artist(db.Model): __tablename__ = 'Artist' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String) city = db.Column(db.String(120)) state = db.Column(db.String(120)) phone = db.Column(db.String(120)) genres = db.Column(db.String(120)) image_link = db.Column(db.String(500)) facebook_link = db.Column(db.String(120))
HTML前端代码
/create-artist页面
{% extends "artists.html" %} {% block title %}New artist | Fy-yur{% endblock %} {% block content %} <div class="container"> <h1>This is the create artist page!</h1> <form id="artist-form" class="col-md-4"> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" placeholder="New Artist"> </div> <div class="form-group"> <label for="city">City</label> <input type="text" class="form-control" id="city" placeholder="Artist's City"> </div> <div class="form-group"> <label for="state">State</label> <select class="form-control" id="state"> </select> </div> <div class="form-group"> <label for="phone">Phone</label> <input type="text" class="form-control" id="phone" placeholder="Phone number"> </div> <div class="form-group"> <label for="genres">Genre</label> <select type="text" class="form-control" id="genres"> </select> </div> <button type="submit" id="submit" class="btn btn-success">Create</button> </form> </div> <script> document.getElementById('artist-form').onsubmit = e => { e.preventDefault(); const body = {}; const formData = e.target; for (let i = 0; i < formData.length - 1; i++) { const currDataKey = formData[i].id; const currDataValue = formData[i].value body[currDataKey] = currDataValue; } fetch('/create-artist', { method: 'POST', body: JSON.stringify(body), headers: { 'Content-Type': 'application/json' } }) .then(res => console.log(res)) .catch(e => console.log(e)); } </script> {% endblock %}
/artists-list页面
{% extends "index.html" %} {% block title %}Artists | Fy-yur{% endblock %} {% block content %} <h1>This is the artists page!</h1> <div class="container"> <a href={{ url_for('create_artist') }}> <button type="button" class="btn btn-success"> New artist </button> </a> </div> {% endblock %}
问题原因及解决办法
原因
你通过fetch发起了AJAX请求,服务器返回的302重定向只会被fetch内部处理(所以日志中能看到GET /artists-list的请求),但AJAX请求的重定向不会触发浏览器地址栏变化或页面跳转。
解决办法
方法一:使用表单默认提交方式
删除表单的onsubmit事件处理代码,给表单添加method="POST"和action="/create-artist"属性,让浏览器自动处理重定向:
<form id="artist-form" class="col-md-4" method="POST" action="/create-artist">
同时后端代码要改用request.form获取数据(默认表单提交是application/x-www-form-urlencoded格式,不是JSON):
artist = Artist( name = request.form['name'], city = request.form['city'], state = request.form['state'], phone = request.form['phone'], genres = request.form['genres'], )
方法二:保留AJAX并手动处理跳转
在fetch的响应回调中,判断是否为重定向,然后手动跳转页面:
fetch('/create-artist', { method: 'POST', body: JSON.stringify(body), headers: { 'Content-Type': 'application/json' } }) .then(res => { if (res.redirected) { window.location.href = res.url; } else { console.log(res); } }) .catch(e => console.log(e));
或者后端返回JSON格式的跳转指令,前端根据返回值跳转:
后端修改:
from flask import jsonify # ... 其他代码 ... if not error: return jsonify({'redirect': url_for('artists_list')})
前端修改:
fetch('/create-artist', { method: 'POST', body: JSON.stringify(body), headers: { 'Content-Type': 'application/json' } }) .then(res => res.json()) .then(data => { if (data.redirect) { window.location.href = data.redirect; } }) .catch(e => console.log(e));
内容的提问来源于stack exchange,提问作者Martin Carre
相关产品推荐
相关产品推荐

