AttributeError: 'WSGIRequest' object has no attribute 'app'

AttributeError: 'WSGIRequest' object has no attribute 'app'

按照建议 here,我在本地计算机上使用这些命令构建 Saleor 仪表板,然后将其复制到远程服务器:

cd ~/repos/fork/saleor-dashboard
git checkout 2.11.1
npm14 --verbose install
export API_URI="https://api.mydomain.com/graphql/"
export GTM_ID="GTM-K9ZZ3R8"
npm14 run build
ls build/dashboard/
scp -i ~/Documents/webserver-key-pair.pem -r build/dashboard ec2-user@3.1.16.71:/srv/www/mydomain/

问题

仪表板可在线使用。但是当我使用有效的 user/pass 登录时,Saleor API 抛出这些错误,由 sudo journalctl -xe:

可见
[20/Jul/2021 02:43:43] "OPTIONS /graphql// HTTP/1.0" 200 0
[20/Jul/2021 02:43:44] "POST /graphql// HTTP/1.0" 200 23728
[20/Jul/2021 02:43:58] "OPTIONS /graphql// HTTP/1.0" 200 0
[20/Jul/2021 02:43:58] "POST /graphql// HTTP/1.0" 200 1971
Traceback (most recent call last):
   File "/home/ec2-user/repos/fork/saleor/saleor-venv/lib64/python3.9/site-packages/promise/promise.py", line 489, in _resolve_from_executor
     executor(resolve, reject)
   File "/home/ec2-user/repos/fork/saleor/saleor-venv/lib64/python3.9/site-packages/promise/promise.py", line 756, in executor
     return resolve(f(*args, **kwargs))
   File "/home/ec2-user/repos/fork/saleor/saleor-venv/lib64/python3.9/site-packages/graphql/execution/middleware.py", line 75, in make_it_promise
     return next(*args, **kwargs)
   File "/home/ec2-user/repos/fork/saleor/saleor/graphql/core/fields.py", line 164, in connection_resolver
     iterable = resolver(root, info, **args)
   File "/home/ec2-user/repos/fork/saleor/saleor/graphql/product/schema.py", line 297, in resolve_products
     return resolve_products(info, **kwargs)
   File "/home/ec2-user/repos/fork/saleor/saleor/graphql/product/resolvers.py", line 49, in resolve_products
     user = get_user_or_app_from_context(info.context)
   File "/home/ec2-user/repos/fork/saleor/saleor/graphql/utils/__init__.py", line 128, in get_user_or_app_from_context
     return context.app or context.user
 graphql.error.located_error.GraphQLLocatedError: 'WSGIRequest' object has no attribute 'app'
 ERROR saleor.graphql.errors.unhandled A query failed unexpectedly [PID:8388:Thread-117]
 Traceback (most recent call last):
   File "/home/ec2-user/repos/fork/saleor/saleor-venv/lib64/python3.9/site-packages/promise/promise.py", line 489, in _resolve_from_executor
     executor(resolve, reject)
   File "/home/ec2-user/repos/fork/saleor/saleor-venv/lib64/python3.9/site-packages/promise/promise.py", line 756, in executor
     return resolve(f(*args, **kwargs))
   File "/home/ec2-user/repos/fork/saleor/saleor-venv/lib64/python3.9/site-packages/graphql/execution/middleware.py", line 75, in make_it_promise
     return next(*args, **kwargs)
   File "/home/ec2-user/repos/fork/saleor/saleor/graphql/core/fields.py", line 164, in connection_resolver
     iterable = resolver(root, info, **args)
   File "/home/ec2-user/repos/fork/saleor/saleor/graphql/product/schema.py", line 297, in resolve_products
     return resolve_products(info, **kwargs)
   File "/home/ec2-user/repos/fork/saleor/saleor/graphql/product/resolvers.py", line 49, in resolve_products
     user = get_user_or_app_from_context(info.context)
   File "/home/ec2-user/repos/fork/saleor/saleor/graphql/utils/__init__.py", line 128, in get_user_or_app_from_context
     return context.app or context.user
 AttributeError: 'WSGIRequest' object has no attribute 'app'
 [20/Jul/2021 02:43:59] "POST /graphql// HTTP/1.0" 200 3192

可能是什么原因?我该如何调试它?谢谢! =)

备注

当我 运行 在 API 和本地仪表板时,在 localhost127.0.0.1 上,一切都很好。当我 运行 API 服务器并在其上部署仪表板时抛出上述错误。

更新

我正在使用 NGINX 为 Saleor API、仪表板和店面提供服务:


    server {
        server_name mydomain.com;
        root /srv/www/mydomain.com/storefront;

        location / {
            index  index.html index.htm;
        }
    }

    server {
        server_name dashboard.mydomain.com;
        root /srv/www/mydomain.com/dashboard;

        location / {
            index  index.html index.htm;
        }
    }

    server {
        server_name api.mydomain.com;

        location / {
            proxy_pass http://127.0.0.1:8000/;
        }
        location /graphql {
            proxy_pass http://127.0.0.1:8000/graphql/;
        }
    }

我觉得既然网络应用程序是 WSGI 一个,NGINX 配置应该不同。有什么想法吗?

更新:测试 NGINX

之前我在本地运行SaleorAPI和Saleor店面时,没有报错

但是我做了一个测试。我什至将 NGINX 用于 localhost 通信:

    server {
        listen 8001;
        server_name localhost;

        location / {
            proxy_pass http://127.0.0.1:8000/;
        }
        location /graphql {
            proxy_pass http://127.0.0.1:8000/graphql/;
        }
    }

然后我开始店面:

cd ~/repos/fork/saleor-storefront
export GTM_ID="GTM-K7ZZ3R1"                    
export API_URI="http://localhost:8001/graphql/"
npm14 start

ℹ 「wds」: Project is running at http://localhost:3000/

然后浏览器DevTools控制台抛出同样的错误:

结论

看起来 NGINX 是问题的原因。

通过 uwsgi 模块启动后端 Django 服务器解决了问题:

  cd /home/ec2-user/repos/fork/saleor
  source saleor-venv/bin/activate
  export DEBUG="False"
  export ALLOWED_CLIENT_HOSTS="localhost,127.0.0.1,dashboard.mydomain.com,mydomain.com,api.mydomain.com"
  export ALLOWED_GRAPHQL_ORIGINS="*"
  export ALLOWED_HOSTS=".localhost,127.0.0.1,.mydomain.com"
  export CREATE_IMAGES_ON_DEMAND="False"
  export DEFAULT_COUNTRY="US"
  export DEFAULT_CURRENCY="USD"
  export SECRET_KEY="Some random text!"
  ### In production, UWSGI is required rather than this:
  #python3.9 manage.py runserver
  python3.9 -m pip install uwsgi
  ### HTTP is just for testing:
  #uwsgi --http :8000 --ini saleor/wsgi/uwsgi.ini
  ### SOCKET is required for NGINX:
  uwsgi --socket :8000 --ini saleor/wsgi/uwsgi.ini

并使用 NGINX 通过 uwsgi 协议(而不是 http 协议)将请求传递到后端 Django 服务器:

http {

    # the upstream component nginx needs to connect to
    # for Saleor API
    upstream django_api {
        server 127.0.0.1:8000;
    }

    server {
        server_name api.mydomain.com;

        charset     utf-8;
        
        # max upload size
        client_max_body_size 75M;

        # Django media
        location /media  {
            alias /home/ec2-user/repos/fork/saleor/media;
        }

        location /static {
            alias /home/ec2-user/repos/fork/saleor/static;
        }   

        # Finally, send all non-media requests to the Django server.
        location / {
            uwsgi_pass django_api;
            include /home/ec2-user/repos/fork/saleor/uwsgi_params;
        }

        location /graphql {
            uwsgi_pass django_api;
            include /home/ec2-user/repos/fork/saleor/uwsgi_params;
        }

        #location / {
        #    proxy_pass http://127.0.0.1:8000/;
        #}
        #location /graphql {
        #    proxy_pass http://127.0.0.1:8000/graphql/;
        #}


    }

}

文档在这里:

https://uwsgi.readthedocs.io/en/latest/tutorials/Django_and_nginx.html