我是网络开发新手,所以很可能我在这里遗漏了一些非常明显的东西,感谢任何人的帮助。
当我在表单上使用 hx-post 时,我在 Chrome 中遇到混合内容错误,即使我指定 url 包含 https 或将 _scheme 提供给 url_for Flask 函数也是如此。
我正在尝试制作一个简单的网页,允许用户下载输入模板,上传完成的模板,在输入上运行脚本,然后下载结果文件。
我使用的是 Flask,服务器是 Gunicorn,它托管在 Azure Web 应用服务上。
完整网页 HTML:
<!doctype html>
<head>
<title>My app</title>
<link rel="stylesheet" href="{{ url_for('static', filename='bootstrap/css/bootstrap.min.css') }}">
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
<script src="static/bootstrap/htmx/htmx.2.0.3.min.js"></script>
<script src="static/bootstrap/htmx/hyperscript.min.js"></script>
</head>
<html>
<body>
<main>
<div class="px-4 py-3 my-2 text-center">
<img class="d-block mx-auto mb-4" src="{{ url_for('static', filename='images/image.jpg') }}"
alt="Logo" width="384" height="192" />
<h1 class="display-6 fw-bold text-primary">Welcome to The App</h1>
</div>
<div class="px-4 py-3 my-2 text-center">
<form method="post" action="{{ url_for('template_download') }}">
<div class="col-md-6 mx-auto">
<label for="name" class="form-label fw-bold fs-3">1. Download the Input Template</label>
<div class="d-grid gap-2 d-sm-flex justify-content-sm-center my-2">
<button type="submit" class="btn btn-primary btn-lg px-4 gap-3">Download</button>
</div>
</div>
</form>
</div>
<div class="px-4 py-3 my-2 text-center">
<form hx-encoding='multipart/form-data' hx-post="/input_upload">
<div class="col-md-6 mx-auto">
<label for="input_file" class="form-label fw-bold fs-3">2. Select the Completed Input File</label>
<p><input type='file' name='input_file'></p>
<div class="d-grid gap-2 d-sm-flex justify-content-sm-center my-2">
<button class="btn btn-primary btn-lg px-4 gap-3">
Upload
</button>
</div>
</div>
</form>
</div>
</main>
</body>
</html>
导致问题的具体部分:
<div class="px-4 py-3 my-2 text-center">
<form hx-encoding='multipart/form-data' hx-post="/input_upload">
<div class="col-md-6 mx-auto">
<label for="input_file" class="form-label fw-bold fs-3">2. Select the Completed Input File</label>
<p><input type='file' name='input_file'></p>
<div class="d-grid gap-2 d-sm-flex justify-content-sm-center my-2">
<button class="btn btn-primary btn-lg px-4 gap-3">
Upload
</button>
</div>
</div>
</form>
</div>
我还在 hx-post 字段中尝试过
"{{ url_for('input_upload', _scheme='https', _external=True) }}"
,以及页面的显式完整 https url。所有这些都会产生混合内容错误。
我也在没有 HTMX 的情况下尝试过,并得到了 400 错误,我不明白:
<div class="px-4 py-3 my-2 text-center">
<form method="post" action="{{ url_for('input_upload') }}" enctype="multipart/form-data">
<div class="col-md-6 mx-auto">
<label for="file" class="form-label fw-bold fs-3">2. Select the Completed Input File</label>
<p><input type="file" name="file"></p>
<div class="d-grid gap-2 d-sm-flex justify-content-sm-center my-2">
<button type="submit" class="btn btn-primary btn-lg px-4 gap-3">Upload</button>
</div>
</div>
</form>
</div>
当我尝试上传后检查页面时,使用 url_for 时,我在 hx-post 字段中看到完整的 https url,但混合内容错误消息显示 http:
混合内容:“https://
/”页面是通过 HTTPS 加载的,但请求了不安全的 XMLHttpRequest 端点“http:// /input_upload”。该请求已被阻止;内容必须通过 HTTPS 提供。
我不明白是什么原因造成的,所以非常感谢任何帮助。
附注这也是网站的 app.py:
import os
import logging
from werkzeug.utils import secure_filename
from flask import (
Flask,
redirect,
render_template,
request,
send_from_directory,
url_for,
)
# Sets logging level to DEBUG.
logging.basicConfig(filename="record.log", level=logging.DEBUG)
# Start and configure the Flask app.
app = Flask(__name__)
app.config["MAX_CONTENT_LENGTH"] = 1024 * 1024 * 10 # 10 MB limit
app.config["UPLOAD_EXTENSIONS"] = [".xlsx", ".xlsm"]
app.config["UPLOAD_PATH"] = "uploads"
app.config["PREFERRED_URL_SCHEME"] = "https"
# Filesize validation. Automatically detected by Flask based on the configuration.
@app.errorhandler(413)
def too_large(e):
return "File is too large", 413
def allowed_file(filename):
return (
"." in filename
and filename.rsplit(".", 1)[1].lower() in app.config["UPLOAD_EXTENSIONS"]
)
# App Page Routing.
@app.route("/")
def index():
app.logger.debug("Request for index page received")
return render_template("index.html")
@app.route("/favicon.ico")
def favicon():
app.logger.debug("Request for favicon received")
return send_from_directory(
os.path.join(app.root_path, "static"),
"favicon.ico",
mimetype="image/vnd.microsoft.icon",
)
@app.route("/template_download", methods=["POST"])
def template_download():
app.logger.debug("Request for template download received")
return send_from_directory(
os.path.join(app.root_path, "static"),
"<filename>.xlsm",
mimetype="application/vnd.ms-excel.sheet.macroEnabled.12",
)
@app.route("/input_upload", methods=["POST"])
def input_upload():
app.logger.debug("Request for input upload received")
if request.files:
input_file = request.files["input_file"]
if input_file.filename == "":
app.logger.debug("No file selected")
return redirect(request.url)
else:
if allowed_file(input_file.filename):
# Gets the username from the email address in header.
name = request.headers["X-MS-CLIENT-PRINCIPAL-NAME"].split("@")[0]
# Creates a folder for the user if it doesn't exist.
os.makedirs(
os.path.join(app.config["UPLOAD_PATH"], name), exist_ok=True
)
# Saves the file to the user's folder. Always overwrites prior input.
input_file.save(
os.path.join(
app.config["UPLOAD_PATH"], name, "input.xlsx"
) # Always save as .xlsx.
)
app.logger.debug(f"User {name} input saved")
return redirect(request.url)
else:
app.logger.debug("File type not allowed")
return redirect(request.url)
@app.route("/output_download", methods=["POST"])
def output_download():
app.logger.debug("Request for output download received")
pass
if __name__ == "__main__":
app.run(
# debug=True,
)
我尝试了你的代码并部署到 Azure Web 应用程序,没有任何问题。
混合内容错误是由于通过 HTTPS 提供服务的网站上的 HTTP 和 HTTPS 请求之间存在冲突造成的。
Azure Blob Storage
来存储上传的文件,因为它提供长期存储和文章访问。Https only
。
我对你的应用程序做了一些小改动。 py 然后它对我来说效果很好。
app.config["UPLOAD_EXTENSIONS"] = ["xlsx", "xlsm"]
@app.route("/input_upload", methods=["POST"])
def input_upload():
app.logger.debug("Request for input upload received")
if 'input_file' not in request.files:
app.logger.debug("No file part in the request")
return redirect(url_for('index'))
input_file = request.files["input_file"]
if input_file.filename == "":
app.logger.debug("No file selected")
return redirect(url_for('index'))
if allowed_file(input_file.filename):
name = request.headers.get("X-MS-CLIENT-PRINCIPAL-NAME", "default_user").split("@")[0]
user_folder = os.path.join(app.config["UPLOAD_PATH"], name)
os.makedirs(user_folder, exist_ok=True)
save_path = os.path.join(user_folder, "input.xlsx")
input_file.save(save_path)
app.logger.debug(f"User {name} input saved at {save_path}")
return redirect(url_for('index'))
else:
app.logger.debug("File type not allowed")
return redirect(url_for('index'))
下面是我的app的完整代码。 py:
import os
import logging
from flask import Flask, redirect, render_template, request, send_from_directory, url_for
logging.basicConfig(filename="record.log", level=logging.DEBUG)
app = Flask(__name__)
app.config["MAX_CONTENT_LENGTH"] = 1024 * 1024 * 10 # 10 MB limit
app.config["UPLOAD_EXTENSIONS"] = ["xlsx", "xlsm"]
app.config["UPLOAD_PATH"] = "uploads"
app.config["PREFERRED_URL_SCHEME"] = "https"
@app.errorhandler(413)
def too_large(e):
return "File is too large", 413
def allowed_file(filename):
return (
"." in filename
and filename.rsplit(".", 1)[1].lower() in app.config["UPLOAD_EXTENSIONS"]
)
@app.route("/")
def index():
app.logger.debug("Request for index page received")
return render_template("index.html")
@app.route("/favicon.ico")
def favicon():
app.logger.debug("Request for favicon received")
return send_from_directory(
os.path.join(app.root_path, "static"),
"favicon.ico",
mimetype="image/vnd.microsoft.icon",
)
@app.route("/template_download", methods=["GET", "POST"])
def template_download():
app.logger.debug("Request for template download received")
return send_from_directory(
os.path.join(app.root_path, "static"),
"template.xlsm", # Replace with your actual file name
mimetype="application/vnd.ms-excel.sheet.macroEnabled.12",
as_attachment=True
)
@app.route("/input_upload", methods=["POST"])
def input_upload():
app.logger.debug("Request for input upload received")
if 'input_file' not in request.files:
app.logger.debug("No file part in the request")
return redirect(url_for('index'))
input_file = request.files["input_file"]
if input_file.filename == "":
app.logger.debug("No file selected")
return redirect(url_for('index'))
if allowed_file(input_file.filename):
name = request.headers.get("X-MS-CLIENT-PRINCIPAL-NAME", "default_user").split("@")[0]
user_folder = os.path.join(app.config["UPLOAD_PATH"], name)
os.makedirs(user_folder, exist_ok=True)
save_path = os.path.join(user_folder, "input.xlsx")
input_file.save(save_path)
app.logger.debug(f"User {name} input saved at {save_path}")
return redirect(url_for('index'))
else:
app.logger.debug("File type not allowed")
return redirect(url_for('index'))
@app.route("/output_download", methods=["POST"])
def output_download():
app.logger.debug("Request for output download received")
pass
if __name__ == "__main__":
app.run(debug=True)
Azure 应用程序服务输出: