質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.34%
Flask

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

180閲覧

FLASK サーバーでなぜか静的ファイルへのリクエストがフォルダに置き換わってしまう

DoubleJ794

総合スコア20

Flask

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2024/12/26 06:19

編集2024/12/26 06:25

実現したいこと

ファイルとフォルダの区別をつけれるように、リクエストを正常に取得したい。
現状、ファイルへのリクエスト時もフォルダへのリクエストだとFLASKが認識して、正常に機能しない。

発生している問題・分からないこと

https:/example.com/aaa/n10440102/71921040_p2.jpg にアクセスしても、 https:/example.com/aaa/n10440102/71921040_p2.jpg/ に飛ばされる
この時、ログは リクエストの時点で https:/example.com/aaa/n10440102/71921040_p2.jpg/ であると認識している

https:/example.com//aaa/n10440102/71921040_p2.jpg へアクセスすると正常に表示される

該当のソースコード

Python

1import os 2import json 3import random 4 5import time 6from datetime import datetime, timedelta 7 8import requests 9 10import threading 11import queue 12 13from flask import Flask, request, jsonify, abort, send_from_directory, Response, redirect, url_for 14 15#ログを保存 16import logging 17 18# 共通設定の読み込み 19import util 20 21class NoNewlineFormatter(logging.Formatter): 22 """改行をスペースに置き換えるフォーマッター""" 23 def format(self, record): 24 message = super().format(record) 25 # 改行をスペースに置き換える 26 return message.replace("\n", " ").replace("\r", " ") 27 28def setup_logging(log_path): 29 """ログ設定を初期化""" 30 # 共通フォーマット 31 common_format = '%(asctime)s - %(levelname)s - %(message)s' 32 33 # コンソールログ(改行そのまま) 34 console_handler = logging.StreamHandler() 35 console_handler.setFormatter(logging.Formatter(common_format)) 36 37 # ファイルログ(改行を除去) 38 file_handler = logging.FileHandler(os.path.join(log_path, 'server.log'), encoding='utf-8') 39 file_handler.setFormatter(NoNewlineFormatter(common_format)) 40 41 # ログ設定 42 logging.basicConfig( 43 level=logging.DEBUG, # DEBUGレベル以上を記録 44 handlers=[console_handler, file_handler] 45 ) 46 47 48def create_app(config, reload_time, auto_update, interval, auto_update_interval, site_dic, login_dic, folder_path, data_path, cookie_path, log_path, key, use_ssl, port, domain, use_proxy, proxy_port, proxy_ssl): 49 setup_logging(log_path) 50 logging.debug(f"サーバー起動") 51 52 app = Flask(__name__) 53 app.config['DATA_FOLDER'] = data_path 54 app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0 # キャッシュ無効化(開発用) 55 app.config['TEMPLATES_AUTO_RELOAD'] = True 56 app.url_map.strict_slashes = True # スラッシュの有無に関わらず対応 57 58 # セキュリティ: ファイルパスを正規化し、安全性を確保 59 def secure_path(requested_path): 60 abs_data_folder = os.path.abspath(app.config['DATA_FOLDER']) 61 abs_requested_path = os.path.abspath(requested_path) 62 63 if not abs_requested_path.startswith(abs_data_folder): 64 raise ValueError(f"Access to this path is outside of the allowed directory: {requested_path}") 65 return abs_requested_path 66 67 @app.before_request 68 def log_request(): 69 """リクエストのログ出力""" 70 logging.info(f"Request URL: {request.url}") 71 logging.info(f"Request Path: {request.path}") 72 73 @app.route('/', methods=["GET"]) 74 def serve_root(): 75 """ルート (/) にアクセスされた場合、index.html を返す""" 76 index_path = os.path.join(app.config['DATA_FOLDER'], "index.html") 77 if os.path.exists(index_path): 78 logging.info(f"Serving root index.html from: {index_path}") 79 return send_from_directory(app.config['DATA_FOLDER'], "index.html") 80 else: 81 logging.error(f"File not found: {index_path}") 82 return jsonify({"status": "error", "message": "File not found"}), 404 83 84 @app.route('/<path:path>', methods=["GET"]) 85 def handle_request(path): 86 """指定されたパスがフォルダかファイルかを確認し、適切に処理""" 87 file_path = os.path.join(app.config['DATA_FOLDER'], path) 88 folder_path = os.path.join(app.config['DATA_FOLDER'], path) 89 90 try: 91 # セキュアなパスか確認 92 secure_path(file_path) 93 except ValueError as e: 94 logging.error(f"Unauthorized access attempt: {e}") 95 return jsonify({"status": "error", "message": "Access denied"}), 403 96 97 if os.path.isfile(file_path): 98 logging.info(f"Serving file from: {file_path}") 99 return send_from_directory(app.config['DATA_FOLDER'], path) 100 101 elif os.path.isdir(folder_path): 102 if not path.endswith('/'): 103 # フォルダの場合、末尾に / を追加してリダイレクト 104 return redirect(url_for('handle_request', path=f'{path}/')) 105 106 index_file = os.path.join(folder_path, "index.html") 107 if os.path.exists(index_file): 108 logging.info(f"Serving index.html from folder: {index_file}") 109 return send_from_directory(folder_path, "index.html") 110 else: 111 logging.warning(f"Folder or index.html not found: {folder_path}") 112 return jsonify({"status": "error", "message": "Folder or index.html not found"}), 404 113 114 else: 115 logging.error(f"Not found: {file_path}") 116 return jsonify({"status": "error", "message": "Not found"}), 404 117 118 return app 119 120# エクスポートされる関数 121def http_run(config, reload_time, auto_update, interval, auto_update_interval, site_dic, login_dic, folder_path, data_path, cookie_path, log_path, key, use_ssl, ssl_crt, ssl_key, port, domain, use_proxy, proxy_port, proxy_ssl): 122 123 # Flask サーバーをバックグラウンドスレッドで実行 (debug=False) 124 if use_ssl: 125 app = create_app(config, reload_time, auto_update, interval, auto_update_interval, site_dic, login_dic, folder_path, data_path, cookie_path, log_path, key, use_ssl, port, domain, use_proxy, proxy_port, proxy_ssl) 126 server_thread = threading.Thread(target=app.run, kwargs={'debug': False, 'threaded': True, 'port': port, 'ssl_context': (ssl_crt, ssl_key)}) 127 else: 128 app = create_app(config, reload_time, auto_update, interval, auto_update_interval, site_dic, login_dic, folder_path, data_path, cookie_path, log_path, key, use_ssl, port, domain, use_proxy, proxy_port, proxy_ssl) 129 server_thread = threading.Thread(target=app.run, kwargs={'debug': False, 'threaded': True, 'port': port}) 130 131 server_thread.daemon = True 132 server_thread.start() 133 134 # サーバーが動作している間、メインスレッドで待機 135 while True: 136 time.sleep(1)

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

リクエストURLのリダイレクト処理より前にあるアクセスログの時点でおかしいので、FLASKの設定にどこか問題はある。

補足

(https:/example.com/aaa/n10440102/71921040_p2.jpg でアクセスしたときのログ)
2024-12-26 15:10:03,866 - INFO - Request URL: https:/example.com/aaa/n10440102/71921040_p2.jpg/
2024-12-26 15:10:03,867 - INFO - Request Path: /aaa/n10440102/71921040_p2.jpg/
2024-12-26 15:10:03,867 - ERROR - Not found: /フォルダ/aaa/n10440102/71921040_p2.jpg/
2024-12-26 15:10:03,868 - INFO - 127.0.0.1 - - [26/Dec/2024 15:10:03] "GET /aaa/n10440102/71921040_p2.jpg/ HTTP/1.1" 404 -
(https:/example.com//aaa/n10440102/71921040_p2.jpg でアクセスしたときのログ)
2024-12-26 15:10:06,514 - INFO - Request URL: https:/example.com//aaa/n10440102/71921040_p2.jpg
2024-12-26 15:10:06,514 - INFO - Request Path: /aaa/n10440102/71921040_p2.jpg
2024-12-26 15:10:06,515 - INFO - Serving file from: /フォルダ/aaa/n10440102/71921040_p2.jpg
2024-12-26 15:10:06,524 - INFO - 127.0.0.1 - - [26/Dec/2024 15:10:06] "GET /aaa/n10440102/71921040_p2.jpg HTTP/1.1" 304 -

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

雑に動かして確認してみました。
(create_appの引数全部消したり、folder_pathはfolder_path = os.path.dirname(os.path.abspath(__file__))としたり)
実際の値が不明ですが、Flask側は正しく動いているように見えます。

設定値あたりが怪しく感じます。
どういう値を設定しているのでしょうか?

投稿2025/01/07 02:41

FiroProchainezo

総合スコア2441

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

DoubleJ794

2025/01/07 07:45

おかしいところは特にない感じですか... 設定ファイルやパラメーターを弄っていないのに、本当になぜか直ったのでちょっともう再現できないんですよね... 設定値は基本的に、configと OO_path と domain 以外は int 型の 0,1 な感じですね... 検証までしていただきありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.34%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問