Docker部署Flask天气服务请求返回404错误,如何排查解决?
问题描述
我开发了一个将在Docker中运行的Python脚本,脚本使用Flask框架调用OpenWeatherMap API获取天气数据。脚本、Dockerfile、依赖文件如下:
Python脚本(app.py)
from flask import Flask import requests app = Flask(__name__) api_key = "308b62e9a346baf4145ea2f25ecf480e" @app.route('/') def index(): return 'App Works!' @app.route('/<string:city>/') def weather_by_city(city): url=f'http://api.openweathermap.org/data/2.5/weather?q={city}&appid={api_key}' response = requests.get(url) if response.status_code == 200: data = response.json() temp = (data['main']['temp']-273.15) # Round the temperature to two decimal places. rounded_temp = round(temp, 2) print(f'Temperature: {rounded_temp} Celsius') desc = data['weather'][0]['description'] print(f'Description: {desc}') else: print('Error fetching weather data') if __name__ == '__main__': app.run(host="0.0.0.0", port=5000)
Dockerfile
FROM python:3 ENV PYTHONUNBUFFERED 1 RUN mkdir /app WORKDIR /app COPY requirements.txt /app RUN pip install --upgrade pip RUN pip install -r requirements.txt COPY . /app EXPOSE 5000 CMD [ "python", "app.py"]
requirements.txt
certifi==2019.9.11 chardet==3.0.4 Click==7.0 Flask==1.1.1 idna==2.8 itsdangerous==1.1.0 Jinja2==2.10.3 MarkupSafe==1.1.1 requests==2.31.0 urllib3==2.0.7 Werkzeug==0.16.0
我在包含上述文件的目录中执行以下命令构建并运行容器:
sudo docker build -t weather:v1 . sudo docker run -dit --rm -p 5000:5000 --name weather weather:v1
容器确认处于运行状态,但执行curl http://0.0.0.0:5000/london请求时返回404 Not Found页面。而直接在Python环境中调用OpenWeatherMap API的请求则返回200状态码。请问哪里操作出错了?
问题原因与解决方法
核心错误点
- 路由定义的HTML转义问题:你在路由里写了
@app.route('/<string:city>/'),这里的<是HTML转义字符,Flask无法识别为路由变量的起始符号<,导致这个路由规则完全无效,所以任何匹配/城市名的请求都会返回404。 - 路由斜杠匹配不一致:路由末尾带
/,但你请求的是/london(不带斜杠),即使路由规则正确,Flask默认会重定向到带斜杠的路径,但当前路由规则本身错误,这一步也无法生效。 - 视图函数无客户端响应:当前
weather_by_city函数仅在容器控制台打印数据,没有向请求客户端返回任何响应内容,就算路由修复,客户端也会得到空响应或500错误。
修正后的Python脚本
from flask import Flask, jsonify import requests app = Flask(__name__) api_key = "308b62e9a346baf4145ea2f25ecf480e" @app.route('/') def index(): return 'App Works!' # 修正路由的HTML转义字符,同时设置strict_slashes=False支持带/和不带/的请求 @app.route('/<string:city>', strict_slashes=False) def weather_by_city(city): url = f'http://api.openweathermap.org/data/2.5/weather?q={city}&appid={api_key}' response = requests.get(url) if response.status_code == 200: data = response.json() temp = (data['main']['temp'] - 273.15) rounded_temp = round(temp, 2) desc = data['weather'][0]['description'] # 向客户端返回JSON格式的响应数据 return jsonify({ 'city': city, 'temperature_celsius': rounded_temp, 'description': desc }) else: # 返回错误信息及对应状态码 return jsonify({'error': 'Error fetching weather data'}), response.status_code if __name__ == '__main__': app.run(host="0.0.0.0", port=5000)
后续操作
修正脚本后,重新构建并运行容器:
sudo docker build -t weather:v2 . sudo docker run -dit --rm -p 5000:5000 --name weather weather:v2
现在执行curl http://0.0.0.0:5000/london就能得到正常的JSON格式天气响应了。
内容的提问来源于stack exchange,提问作者GoT GOt
相关产品推荐
相关产品推荐

