Weasyprint 无法在 url 加载图像:名称或服务未知
Weasyprint failed to load image at url: Name or service not known
从 xhtml2pdf 迁移后,我正在使用 weasyprint,我发现获取静态文件存在一些问题。我收到以下错误:
2021-12-03 14:45:50,198 [ERROR] Failed to load image at "http://api.dashboard.localhost:8000/static/logos/logo.png" (URLError: <urlopen error [Errno -2] Name or service not known>)
但是当我访问相同的 URL weasyprint 时,无论是在我的浏览器还是 curl 上,我都无法查看/访问该文件。
这是我的代码:
from io import BytesIO
import mimetypes
from pathlib import Path
from urllib.parse import urlparse
import logging
from django.conf import settings
from django.contrib.staticfiles.finders import find
from django.core.files.storage import default_storage
from django.urls import get_script_prefix
from django.template.loader import render_to_string
import weasyprint
from weasyprint import HTML
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
handlers=[
logging.FileHandler("debug.log"),
logging.StreamHandler()
]
)
# https://github.com/fdemmer/django-weasyprint/blob/main/django_weasyprint/utils.py
def url_fetcher(url, *args, **kwargs):
# load file:// paths directly from disk
if url.startswith('file:'):
mime_type, encoding = mimetypes.guess_type(url)
url_path = urlparse(url).path
data = {
'mime_type': mime_type,
'encoding': encoding,
'filename': Path(url_path).name,
}
default_media_url = settings.MEDIA_URL in ('', get_script_prefix())
if not default_media_url and url_path.startswith(settings.MEDIA_URL):
media_root = settings.MEDIA_ROOT
if isinstance(settings.MEDIA_ROOT, Path):
media_root = f'{settings.MEDIA_ROOT}/'
path = url_path.replace(settings.MEDIA_URL, media_root, 1)
data['file_obj'] = default_storage.open(path)
return data
elif settings.STATIC_URL and url_path.startswith(settings.STATIC_URL):
path = url_path.replace(settings.STATIC_URL, '', 1)
data['file_obj'] = open(find(path), 'rb')
return data
# fall back to weasyprint default fetcher
return weasyprint.default_url_fetcher(url, *args, **kwargs)
def render_template_to_pdf(template_path, request, context):
results = BytesIO()
template_string = render_to_string(
template_name=template_path,
context=context,
)
# create the pdf report
HTML(string=template_string, base_url=request.build_absolute_uri("/"), url_fetcher=url_fetcher).write_pdf(results)
return results.getbuffer()
以上代码生成了 pdf,但没有图像,因为上述错误一直显示在我的日志中。
我的媒体/静态文件设置:
DEFAULT_FILE_STORAGE = "utils.storages.CustomFileSystemStorage"
STATIC_URL = "/static/"
STATIC_ROOT = os.path.realpath(env.str("STATIC_FILES_ROOT", default=os.path.join(BASE_DIR, "staticfiles") + "/"))
MEDIA_URL = "/media/"
MEDIA_ROOT = os.path.realpath(env.str("MEDIA_FILES_ROOT", default=os.path.join(BASE_DIR, "mediafiles") + "/"))
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"),
]
在我的模板中:
{% load static %}
<div style="float: right;">
<img src="{% static 'logos/logo.jpg' %}" alt="logo" width="140" height="40"/>
</div>
我在 docker 中是 运行,但我认为它可能不相关,因为我可以访问应用程序外部的文件(浏览器/curl),但不能使用 weasyprint。
我一直在检查 Whosebug/github/etc 上的答案,但不幸的是找不到解释为什么会发生这种情况或如何解决它的内容。
非常感谢任何关于为什么会发生这种情况的见解!
Docker 不是问题,因为我在使用 static 时也遇到了类似的错误,就像没有 docker 时一样。我收到如下所示的错误:
[weasyprint:137] ERROR: Relative URI reference without a base URI:
所以我所做的是使用 urlsplit 来获取我的应用程序 url 并将其传递给模板以便我可以使用完整的 url.
from django.utils.six.moves.urllib.parse import urlsplit
def test(request):
scheme = urlsplit(request.build_absolute_uri(None))
context = {
'host_url': f"{scheme.scheme}://{scheme.netloc}"
}
return render(request, 'pdf.html', context)
模板
<img src="{{ host_url }}/logos/logo.jpg" alt="" />
您可以直接使用您的域,而不是传递 host_url,但使用 host_url 它会使应用程序动态化,并且您在不同的域中或在使用时不必更改域本地服务器。
我不确定为什么,但是将 base_url
设置为 "."
可以解决问题,weasyprint 现在可以解析本地和外部静态文件。
更改生效时间:
HTML(string=template_string, base_url=".", url_fetcher=url_fetcher).write_pdf(results)
这花了我一整天的时间,在尝试 "."
之前,我查看了 weasyprint 和 django-weasyprint 的源代码。我希望这可以在将来的某个时间拯救任何遇到同样问题的人。
从 xhtml2pdf 迁移后,我正在使用 weasyprint,我发现获取静态文件存在一些问题。我收到以下错误:
2021-12-03 14:45:50,198 [ERROR] Failed to load image at "http://api.dashboard.localhost:8000/static/logos/logo.png" (URLError: <urlopen error [Errno -2] Name or service not known>)
但是当我访问相同的 URL weasyprint 时,无论是在我的浏览器还是 curl 上,我都无法查看/访问该文件。
这是我的代码:
from io import BytesIO
import mimetypes
from pathlib import Path
from urllib.parse import urlparse
import logging
from django.conf import settings
from django.contrib.staticfiles.finders import find
from django.core.files.storage import default_storage
from django.urls import get_script_prefix
from django.template.loader import render_to_string
import weasyprint
from weasyprint import HTML
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
handlers=[
logging.FileHandler("debug.log"),
logging.StreamHandler()
]
)
# https://github.com/fdemmer/django-weasyprint/blob/main/django_weasyprint/utils.py
def url_fetcher(url, *args, **kwargs):
# load file:// paths directly from disk
if url.startswith('file:'):
mime_type, encoding = mimetypes.guess_type(url)
url_path = urlparse(url).path
data = {
'mime_type': mime_type,
'encoding': encoding,
'filename': Path(url_path).name,
}
default_media_url = settings.MEDIA_URL in ('', get_script_prefix())
if not default_media_url and url_path.startswith(settings.MEDIA_URL):
media_root = settings.MEDIA_ROOT
if isinstance(settings.MEDIA_ROOT, Path):
media_root = f'{settings.MEDIA_ROOT}/'
path = url_path.replace(settings.MEDIA_URL, media_root, 1)
data['file_obj'] = default_storage.open(path)
return data
elif settings.STATIC_URL and url_path.startswith(settings.STATIC_URL):
path = url_path.replace(settings.STATIC_URL, '', 1)
data['file_obj'] = open(find(path), 'rb')
return data
# fall back to weasyprint default fetcher
return weasyprint.default_url_fetcher(url, *args, **kwargs)
def render_template_to_pdf(template_path, request, context):
results = BytesIO()
template_string = render_to_string(
template_name=template_path,
context=context,
)
# create the pdf report
HTML(string=template_string, base_url=request.build_absolute_uri("/"), url_fetcher=url_fetcher).write_pdf(results)
return results.getbuffer()
以上代码生成了 pdf,但没有图像,因为上述错误一直显示在我的日志中。
我的媒体/静态文件设置:
DEFAULT_FILE_STORAGE = "utils.storages.CustomFileSystemStorage"
STATIC_URL = "/static/"
STATIC_ROOT = os.path.realpath(env.str("STATIC_FILES_ROOT", default=os.path.join(BASE_DIR, "staticfiles") + "/"))
MEDIA_URL = "/media/"
MEDIA_ROOT = os.path.realpath(env.str("MEDIA_FILES_ROOT", default=os.path.join(BASE_DIR, "mediafiles") + "/"))
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"),
]
在我的模板中:
{% load static %}
<div style="float: right;">
<img src="{% static 'logos/logo.jpg' %}" alt="logo" width="140" height="40"/>
</div>
我在 docker 中是 运行,但我认为它可能不相关,因为我可以访问应用程序外部的文件(浏览器/curl),但不能使用 weasyprint。
我一直在检查 Whosebug/github/etc 上的答案,但不幸的是找不到解释为什么会发生这种情况或如何解决它的内容。 非常感谢任何关于为什么会发生这种情况的见解!
Docker 不是问题,因为我在使用 static 时也遇到了类似的错误,就像没有 docker 时一样。我收到如下所示的错误:
[weasyprint:137] ERROR: Relative URI reference without a base URI:
所以我所做的是使用 urlsplit 来获取我的应用程序 url 并将其传递给模板以便我可以使用完整的 url.
from django.utils.six.moves.urllib.parse import urlsplit
def test(request):
scheme = urlsplit(request.build_absolute_uri(None))
context = {
'host_url': f"{scheme.scheme}://{scheme.netloc}"
}
return render(request, 'pdf.html', context)
模板
<img src="{{ host_url }}/logos/logo.jpg" alt="" />
您可以直接使用您的域,而不是传递 host_url,但使用 host_url 它会使应用程序动态化,并且您在不同的域中或在使用时不必更改域本地服务器。
我不确定为什么,但是将 base_url
设置为 "."
可以解决问题,weasyprint 现在可以解析本地和外部静态文件。
更改生效时间:
HTML(string=template_string, base_url=".", url_fetcher=url_fetcher).write_pdf(results)
这花了我一整天的时间,在尝试 "."
之前,我查看了 weasyprint 和 django-weasyprint 的源代码。我希望这可以在将来的某个时间拯救任何遇到同样问题的人。