修复HttpErrorResponse 405错误,实现全站HTTPS并禁用HTTP
问题描述
我在VPS上部署了一套采用Flask后端API、Angular前端、Nginx反向代理的网站,已为Nginx配置SSL证书。当前遇到以下问题:
- HTTP请求可正常连接Flask服务(如
http://app.my-domain.com/api/login) - HTTPS请求访问
https://app.my-domain.com/api/login时返回HttpErrorResponse 405 Not Allowed错误 - 需要确保所有请求强制通过HTTPS运行,并禁用HTTP直接访问
现有配置
Nginx配置
server { server_name app.my-domain.com; #expires 0; #add_header Cache-Control private; # flask backend server location /api/* { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $http_host; proxy_pass http://0.0.0.0:5000/; proxy_redirect http://0.0.0.0:5000/ /; } #angular static files location after compilation using ng build --configuration production location / { expires -1; default_type application/javascript; add_header Pragma "no-cache"; add_header Cache-Control "no-store, no-cache, must-revalidate, post-check=0, pre-check=0"; root /root/workspace/FrontEnd/dist; index index.html index.htm; try_files $uri $uri/ /index.html =404; } access_log /var/log/nginx/my-domain.com.access.log; error_log /var/log/nginx/my-domain.com.error.log; listen 443 ssl; # managed by Certbot ssl_certificate /etc/letsencrypt/live/app.my-domain.com/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/app.my-domain.com/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot } server { if ($host = app.my-domain.com) { return 301 https://$host$request_uri; } # managed by Certbot listen 80; listen [::]:80; server_name app.domain.com; return 404; # managed by Certbot }
Angular请求代码
const header=new HttpHeaders({}); const httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json'}), withcredentials: true }; @Injectable({ providedIn: 'root', }) export class AuthService { // create var res constructor(private http: HttpClient) {} private isLogged: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false); login(email: string, password: string): Observable<any> { // pass var res in return const formData = new FormData(); formData.append('email', email); formData.append('password', password); console.log(AUTH_API); return this.http.post( './api/login', formData ); // <---------- } }
Flask后端代码
app = Flask(__name__, static_folder='static', template_folder='static') gunicorn_error_logger = logging.getLogger('gunicorn.error') app.logger.handlers.extend(gunicorn_error_logger.handlers) app.logger.setLevel(logging.DEBUG) db.init_app(app) migrate = Migrate(app, db) CORS(app, resources={r'/*': {'origins': '*'}}, supports_credentials=True) from views import LoginPageView app.add_url_rule('/api/login', view_func=LoginPageView.as_view('login_page', app.logger), methods=['GET','POST']) if __name__ == '__main__': app.run(debug=True)
Flask启动命令
gunicorn --workers 4 --bind 0.0.0.0:5000 wsgi:app --worker-class eventlet
问题排查与修复方案
1. 修正Nginx核心配置问题
(1)修复location匹配规则
原配置中location /api/*的写法不符合Nginx语法,前缀匹配不需要*,会导致HTTPS请求路径转发异常。改为location /api/即可正确匹配所有API路径。
(2)修复HTTP跳转域名不一致问题
原80端口server块的server_name写为app.domain.com,与443块的app.my-domain.com不匹配,导致部分HTTP请求无法正确跳转HTTPS,需统一为app.my-domain.com。
修正后的Nginx配置
server { server_name app.my-domain.com; # flask backend server location /api/ { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $http_host; proxy_pass http://0.0.0.0:5000/; proxy_redirect http://0.0.0.0:5000/ /; } # Angular静态文件(ng build --configuration production编译后目录) location / { expires -1; default_type application/javascript; add_header Pragma "no-cache"; add_header Cache-Control "no-store, no-cache, must-revalidate, post-check=0, pre-check=0"; root /root/workspace/FrontEnd/dist; index index.html index.htm; try_files $uri $uri/ /index.html =404; } access_log /var/log/nginx/my-domain.com.access.log; error_log /var/log/nginx/my-domain.com.error.log; listen 443 ssl; # managed by Certbot ssl_certificate /etc/letsencrypt/live/app.my-domain.com/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/app.my-domain.com/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot } server { listen 80; listen [::]:80; server_name app.my-domain.com; return 301 https://$host$request_uri; }
2. 优化Angular编译配置
编译Angular时建议指定base-href,避免路径跳转后出现异常:
ng build --configuration production --base-href /
3. 验证Flask后端请求接收
在Flask的LoginPageView的post方法中添加日志,确认HTTPS请求是否正确转发:
def post(self): self.logger.debug(f"Received request, scheme: {self.request.scheme}, path: {self.request.path}") # 原有业务逻辑...
4. 生效配置并验证
- 重启Nginx:
sudo systemctl restart nginx - 检查Gunicorn服务状态:
sudo systemctl status gunicorn(若用systemd管理) - 测试HTTPS请求:
curl -X POST https://app.my-domain.com/api/login -F "email=test@example.com" -F "password=123456"
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

