为什么表单元素上的 HTMX hx-post 会导致混合内容错误?

问题描述 投票:0回答:1

我是网络开发新手,所以很可能我在这里遗漏了一些非常明显的东西,感谢任何人的帮助。

当我在表单上使用 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,
    )
python flask azure-web-app-service htmx
1个回答
0
投票

我尝试了你的代码并部署到 Azure Web 应用程序,没有任何问题。

混合内容错误是由于通过 HTTPS 提供服务的网站上的 HTTP 和 HTTPS 请求之间存在冲突造成的。

  • 最好使用
    Azure Blob Storage
    来存储上传的文件,因为它提供长期存储和文章访问。
  • 如果您使用基本或标准应用程序服务计划,请尝试将其升级到高级。
  • 确保在 Azure Web 应用程序的配置部分启用
    Https only
    enter image description here

我对你的应用程序做了一些小改动。 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 应用程序服务输出

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.