[英]Django application running on top of Serverless + Lambda + API Gateway HTTP API is rewriting links to be prefixed with default
我的 Django 應用程序(主要基於 REST 框架)當前在管理頁面上生成無法解析的 URL。 預期結果是 Django 管理員的登錄提示將帶有 POST 的表單提交到/admin/login
。 作為表單提交 URL 通過 Django 傳遞的結果 URL 是/$default/admin/login
並返回 404 和更遲鈍的/$default/$default/admin/login/
。
我假設我的 Django 配置或serverless.yml
中存在某種配置錯誤。
根據以下serverless.yml
,我正在使用 API Gateway V2、Django 通過 WSGI 和 Lambda 函數。
service: api
app: api
org: myapp
frameworkVersion: '3'
provider:
name: aws
runtime: python3.8
functions:
serve:
handler: wsgi_handler.handler
timeout: 20
environment:
DB_NAME: ${param:db_name}
DB_PASSWORD: ${param:db_password}
DB_USER: ${param:db_user}
DB_PORT: ${param:db_port}
DB_HOST: ${param:db_host}
events:
- httpApi: "*"
migration:
handler: migrate.handler
timeout: 60
environment:
DB_NAME: ${param:db_name}
DB_PASSWORD: ${param:db_password}
DB_USER: ${param:db_user}
DB_PORT: ${param:db_port}
DB_HOST: ${param:db_host}
custom:
wsgi:
app: myapp.wsgi.application
plugins:
- serverless-python-requirements
- serverless-wsgi
我的網址非常標准:
from django.contrib import admin
from django.urls import path, include
from rest_framework.schemas import get_schema_view
schema_view = get_schema_view(
title="MyApp",
description="MyApp Universal API",
version="1.0.0",
)
urlpatterns = [
path("admin/", admin.site.urls),
path("user/", include("myapp.core.urls"), name="user"),
path("openapi", schema_view, name="openapi-schema"),
]
我的配置更標准:
import os
from pathlib import Path
from dotenv import load_dotenv
load_dotenv()
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "not for you :)"
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ['*']
if 'CODESPACE_NAME' in os.environ:
codespace_name = os.getenv("CODESPACE_NAME")
codespace_domain = os.getenv("GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN")
CSRF_TRUSTED_ORIGINS = [f'https://{codespace_name}-8000.{codespace_domain}']
ROOT_URLCONF = "myapp.urls"
# Application definition
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
'rest_framework',
"myapp.core",
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
X_FRAME_OPTIONS = "ALLOW-FROM preview.app.github.dev"
ROOT_URLCONF = "myapp.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "myapp" / "templates"],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
WSGI_APPLICATION = "myapp.wsgi.application"
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
# Database
# https://docs.djangoproject.com/en/4.1/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('DB_NAME', 'neondb'),
'USER': os.environ.get('DB_USER', 'postgres'),
'PASSWORD': os.environ.get('DB_PASSWORD'),
'HOST': os.environ.get('DB_HOST', 'localhost'),
'PORT': os.environ.get('DB_PORT', 5432),
}
}
# Password validation
# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
# Internationalization
# https://docs.djangoproject.com/en/4.1/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.1/howto/static-files/
STATICFILES_DIRS = [
BASE_DIR / "myapp" / "static",
]
STATIC_URL = "static/"
# Default primary key field type
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3StaticStorage'
AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = "myapp-django-static"
AUTH_USER_MODEL = 'core.User'
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticatedOrReadOnly',
)
}
至於由此產生的錯誤信息:
任何幫助(或想法)將不勝感激!
我已經嘗試修改serverless.yml
的路徑結構,並且一直在瀏覽 Django 源代碼以尋找任何無濟於事的提示。 當然,我只想讓 Django 管理員工作。 至於應用程序的 rest,它工作正常,因為 API 本身不是自引用的。 Django 只是沒有返回正確的路徑。
簡而言之,Django 認為我所有的路由都以/$default/
為前綴,但事實並非如此。 我正在尋找一種解決方案來強制將 Django 發送的路徑設為/
或修復我的無服務器配置以緩解此問題。
我設法用一個相當小眾的 Django 設置選項解決了這個問題。 https://docs.djangoproject.com/en/4.1/ref/settings/#force-script-name
雖然這並不能解釋為什么要解析到/$default/
的路徑,但它確實緩解了這個問題。
如果您將此用於與我不同的用例並且您的路徑位於子目錄中(例如與我相反的問題),那么您將在FORCE_SCRIPT_NAME
中添加您的路徑。
請參閱我提供的鏈接以獲取更多信息。
將以下內容添加到您應用的settings.py
或您用作DJANGO_SETTINGS_MODULE
的任何文件中。
# Force Django to resolve the URL to the root of the site
# This is required for API Gateway <- WSGI -> Django path resolution to work properly.
FORCE_SCRIPT_NAME = ""
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.