You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

修复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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 05:54:52