概述

Export to PDF 服务是一个服务器端组件,用于将 HTML 内容转换为 PDF 文件。它在主机基础设施内部署于本地环境,可通过两种方式使用:

  • 作为 TinyMCE 编辑器中 Export to PDF 插件的后端。

  • 直接通过其 REST API,独立于编辑器使用。

若要使用 TinyMCE 8.4.0 或更高版本配合 Export to PDF 插件,本地 Docker 镜像必须支持 v2 API(/v2/convert/html-pdf)。请使用最新镜像或兼容 v2 的版本。有关版本详情,请参阅 变更日志。

要在本地运行 Export to PDF Converter 服务,需要有效的服务许可证密钥。此密钥与 TinyMCE 编辑器许可证密钥不同。此外,还需要访问令牌才能访问 Tiny Cloud Docker 仓库并拉取 Docker 镜像。有关更多信息,请参阅 服务许可证密钥。

开始使用前,请联系 Tiny 支持团队获取试用服务许可证密钥和 Docker 访问令牌。

在本地运行 Export to PDF 服务的唯一要求是容器运行时或编排工具,例如 Docker、Kubernetes 或 Podman。

要求

要运行 Export to PDF On-Premises,需要一个 Docker 环境。或者,可以使用云提供商提供的 CaaS(容器即服务),如 AWS ECS、Google GKE 或 Azure ACS。

影响 Export to PDF On-Premises 性能的因素有很多。最主要的是导出内容的尺寸、图像尺寸以及并发请求的数量。此外,由于您的应用程序可能需要优先考虑快速响应时间,或者需要处理高负载,因此无法提供一套适用于所有用例的推荐服务器规格。

假设响应时间在 10 秒以内,一台服务器(2 CPU、2GB RAM)搭配 1 个 Docker 容器可以处理:

  • 最多 40 个并发请求,平均内容为 1 页 A4 纸(约 1k 字符和 1 张图像)

  • 最多 25 个并发请求,平均内容为 5 页 A4 纸(约 7,5k 字符和 5 张图像)

  • 最多 10 个并发请求,平均内容为 20 页 A4 纸(约 30k 字符和 20 张图像)

上述并发请求数量并非 Export to PDF On-Premises 实例的硬性限制。它可以处理更多并发请求,但响应时间会延长。

高可用性

一个带有 Export to PDF On-Premises 的 Docker 容器可以利用机器上的额外 CPU 资源。若要在单台机器上扩展应用程序,可增加 CPU 数量,但 Tiny 建议至少在三个主机上进行扩展,以确保系统的可靠性。

在多台机器上进行扩展时,需要使用负载均衡器,如 HAProxy 或 NGINX(参见 SSL 通信指南中的负载均衡器配置示例)。当然,也可以使用任何云提供商进行扩展,例如 Amazon ECS、Azure Container Instances 或 Kubernetes。

如果您有关于 Export to PDF On-Premises 用例所需服务器资源的任何问题,请联系我们。

安装

运行 Export to PDF 本地服务需要两个独立的凭据:

  • Docker 仓库访问令牌:用于向 Tiny Docker 仓库认证并拉取服务镜像。

  • 服务许可证密钥:用于在运行时启用服务。此密钥与 TinyMCE 编辑器许可证密钥不同。

详情请参阅 服务许可证密钥。联系我们获取试用服务许可证密钥。

支持的技术

该应用程序默认以 Docker 镜像形式提供。

它可以使用任何 Open Container 运行时工具运行,例如 Kubernetes、OpenShift、Podman、Docker 等。

有关运行 Export to PDF On-Premises 所需的硬件和软件要求的更多信息,请参阅要求指南。

使用 Docker 容器设置应用程序

  1. 登录 Docker 仓库并使用提供的访问令牌获取 Docker 镜像。

  2. 使用 docker 或 docker-compose 对应用程序进行容器化。

  3. 使用演示页面验证应用程序是否正常工作。

使用 docker 进行容器化的示例

登录 Docker 仓库:

docker login -u tiny -p [access-token] registry.containers.tiny.cloud

拉取 Docker 镜像:

docker pull registry.containers.tiny.cloud/pdf-converter-tiny:[version]

要查看所有可用的 Docker 镜像版本,请参阅 pdf-converter-tiny 的变更日志。

为确保能够访问服务的最新版本,Tiny推荐在拉取镜像时使用 latest 标签。

启动 Docker 容器:

docker run --init -p 8080:8080 -e LICENSE_KEY="$PDF_LICENSE_KEY" registry.containers.tiny.cloud/pdf-converter-tiny:[version]

将 $PDF_LICENSE_KEY 替换为服务许可证密钥,或将 PDF_LICENSE_KEY 设置为环境变量。有关详情,请参阅 使用特定于服务的环境变量。

如果使用授权,请提供 SECRET_KEY:

docker run --init -p 8080:8080 -e LICENSE_KEY="$PDF_LICENSE_KEY" -e SECRET_KEY=[your_secret_key] registry.containers.tiny.cloud/pdf-converter-tiny:[version]

有关使用授权的更多信息,请参阅授权部分。

使用 docker-compose 进行容器化的示例

  1. 创建 docker-compose.yml 文件:

    version: "3.8"
    services:
      pdf-converter-tiny:
        image: registry.containers.tiny.cloud/pdf-converter-tiny:[version]
        ports:
          - "8080:8080"
        restart: always
        init: true
        environment:
          LICENSE_KEY: "${PDF_LICENSE_KEY}"
          # Secret Key is optional
          SECRET_KEY: "secret_key"
          # Custom request origin is optional
          CUSTOM_REQUEST_ORIGIN: "https://your_custom_origin"

    有关 SECRET_KEY 使用的详情,请检查授权部分。

  2. 运行:

docker compose up
  • 如果没有正确的 LICENSE_KEY,应用程序将无法启动。请在 .env 文件或 shell 环境中设置 PDF_LICENSE_KEY 为有效的服务许可证密钥。

    • 如果许可证无效,日志中将显示错误的许可证密钥信息,且应用程序将无法运行。

  • 出于安全考虑,建议使用唯一且难以猜测的字符串覆盖 SECRET_KEY 变量。

  • 如果特定基础设施启用了严格的 CORS,则使用 CUSTOM_REQUEST_ORIGIN 变量来设置转换器发起的请求的来源。默认值为 https://pdf-internal。

Windows 字体支持

如果在 PDF 文件中使用了 Windows 字体(如 Calibri、Verdana 等),请使用 pdf-converter-windows-tiny Docker 镜像并在 Windows 操作系统上运行它。

有关更多详情,请参阅字体部分。

后续步骤

使用 http://localhost:8080/v1/convert 端点导出 PDF 文件。查看授权部分以了解更多关于令牌和令牌端点的信息。

使用位于 http://localhost:8080/demo 的演示页面生成示例 PDF 文件。

有关更多详情,请参阅位于 http://localhost:8080/docs 的 Export to PDF REST API 文档。

字体

在撰写文档时,能够使用多种不同的字体对用户来说可能非常重要。

使用合适的字体可以改变文档的外观并强调其风格。

Export to PDF Converter 允许使用 Web 字体,这使集成商能够使用标准操作系统字体或使用自定义字体,而无需使用 CSS 导入它们。

以下是镜像中包含的基本字体列表:

OpenSans-Bold.ttf
OpenSans-BoldItalic.ttf
OpenSans-ExtraBold.ttf
OpenSans-ExtraBoldItalic.ttf
OpenSans-Italic.ttf
OpenSans-Light.ttf
OpenSans-LightItalic.ttf
OpenSans-Regular.ttf
OpenSans-Semibold.ttf
OpenSans-SemiboldItalic.ttf

但是,可以通过以下两种方式向 Export to PDF Converter 添加其他字体:

  • 使用类 Unix 环境的 PDF-Converter 镜像 registry.containers.tiny.cloud/pdf-converter-tiny 并将字体目录挂载到其中。

    • 请参阅“向 PDF Converter 添加自定义字体”部分。

  • 使用 Windows PDF-Converter 镜像 registry.containers.tiny.cloud/pdf-converter-tiny,并将运行该容器的 Windows 操作系统上的字体目录挂载到容器中。

    • 请参阅“在 PDF Converter 中使用 Windows 字体”部分。

挂载卷内的字体将安装在 Docker 镜像的操作系统上。仅支持 .ttf 和 .otf 字体格式。如果使用其他字体格式,则需要先将其转换为支持的格式,或者使用如 Web Fonts 之类的字体。
在安装到 Docker 容器之前,请确保这些转换后的字体可以在您的本地机器上安装并使用。

向 PDF Converter 添加自定义字体

如果 PDF 文件中使用了自定义字体,请使用 pdf-converter-tiny Docker 镜像,并将包含自定义字体的目录挂载到在类 Unix 系统(包括带有 WSL 后端的 Docker on Windows)上运行的 PDF Converter 应用程序中。

registry.containers.tiny.cloud/pdf-converter-tiny Docker 镜像需要在类 Unix 操作系统上运行,并挂载 ~/your_fonts_dir:/usr/share/fonts/your_fonts_dir 卷。

在类 Unix 操作系统上启动 Docker 容器的示例:

docker run --init -v ~/your_fonts_dir:/usr/share/fonts/your_fonts_dir -p 8080:8080 -e LICENSE_KEY="$PDF_LICENSE_KEY" registry.containers.tiny.cloud/pdf-converter-tiny:[version]

在 PDF Converter 中使用 Windows 字体

如果在 PDF 文件中使用了 Windows 字体(如 Arial、Verdana 等),请使用 pdf-converter-windows-tiny Docker 镜像,该镜像允许您在 Windows 操作系统的机器上运行应用程序并挂载系统字体。

您只需在 Windows 操作系统上运行 registry.containers.tiny.cloud/pdf-converter-tiny Docker 镜像,并挂载 C:\Windows\Fonts:C:\Windows\Fonts 卷即可。

在 Windows 操作系统上启动 Docker 容器的示例:

docker run -v C:\Windows\Fonts:C:\Windows\Fonts -p 8080:8080 --env LICENSE_KEY="$PDF_LICENSE_KEY" registry.containers.tiny.cloud/pdf-converter-windows-tiny:[version]

授权

要启用授权,请在安装期间设置 SECRET_KEY 环境变量。

如果设置了 SECRET_KEY 变量,则所有请求都必须包含一个使用该密钥签名的 JWT (JSON Web Token) 头部。令牌应作为发送到 Export to PDF REST API 的每个请求的 Authorization 头部的值传递。

如果在安装期间未设置 SECRET_KEY,则 Export to PDF On-Premises 在向 Export to PDF REST API 发送请求时不需要任何包含令牌的头部。然而,不建议在公共网络中运行 Export to PDF On-Premises 时跳过授权。

生成令牌

Tiny 建议使用 jwt.io 上列出的库来生成令牌。当满足以下条件时,令牌被视为有效:

  • 它使用与传递给 Export to PDF On-Premises 实例相同的 SECRET_KEY 签名,

  • 它在过去 24 小时内创建,

  • 它不是在未来发行的(即 iat 时间戳不能晚于当前时间),

  • 它尚未过期。

如果特定用例涉及从后端服务器发送请求,则可以像下面的请求示例所示在本地生成 JWT 令牌。

对于编辑器插件或其他前端用途,应创建一个令牌端点,为授权用户返回有效的 JWT 令牌。

端点实现示例。
const express = require( 'express' );
const jwt = require( 'jsonwebtoken' );

const SECRET_KEY = 'secret_key';

const app = express();

app.use( ( req, res, next ) => {
  res.setHeader( 'Access-Control-Allow-Origin', '*' );
  res.setHeader( 'Access-Control-Allow-Methods', 'GET' );

  next();
});

app.get( '/', ( req, res ) => {
  const result = jwt.sign( {}, SECRET_KEY, { algorithm: 'HS256' } );

  res.send( result );
});

app.listen( 8080, () => console.log( 'Listening on port 8080' ) );

使用编辑器插件

TinyMCE 的插件将自动从给定的 tokenUrl 变量请求令牌,并在进行导出请求时设置 Authorization 头部。

有关如何将 Export to PDF 功能添加到编辑器的详细信息,请参阅 Export to PDF 插件文档。

带 Authorization 头部的请求示例

以下示例展示了一个生成有效 JWT 令牌并将其设置为 Authorization 头部的请求:

const fs = require( 'fs' );
const jwt = require( 'jsonwebtoken' );
const axios = require( 'axios' );

const SECRET_KEY = 'secret';

const token = jwt.sign( {}, SECRET_KEY, { algorithm: 'HS256' } );

const data = {
  html: "<p>I am a teapot</p>",
  css: "p { color: red; }",
};

const config = {
  headers: {
    'Authorization': token
  },
  responseType: 'arraybuffer',
};

axios.post( 'http://localhost:8080/v1/convert', data, config )
  .then( response => {
    fs.writeFileSync('./file.pdf', response.data, 'binary');
  }).catch( error => {
    console.log( error );
   });

SECRET_KEY 是已传递给 Export to PDF On-Premises 实例的密钥。

请参阅 Export to PDF REST API 文档 以开始使用该服务。

如果使用 Postman 或 Insomnia 等 API 客户端,请在 Headers 选项卡中将 JWT 令牌设置为 Authorization 头部。不要使用内置的令牌授权,因为这会生成无效的头部,并在令牌前添加了 Bearer 前缀。

API 用法

Export to PDF On-Premises 转换器提供通过 Restful API 将 HTML 文档转换为 PDF 文件的能力。

API 可在 http://localhost:[port] 上访问(默认情况下 port 为 8080)。

REST API 文档位于 http://localhost:[port]/docs。或者,请参阅 https://exportpdf.api.tiny.cloud/v1/convert/docs 中的规范。

如果启用了 API 授权,请提供授权令牌。更多说明可在授权部分找到。

使用额外的 HTTP 头部

如果在生成的 PDF 中使用某些资源(例如图像)需要以额外 HTTP 头部的形式传递额外的授权因素:

  1. 可以在应用程序启动时通过设置 EXTRA_HTTP_HEADERS 环境变量来定义,其中值为包含所需头部的字符串化 JSON 对象。

  2. 可以在发送到 PDF Converter API 的请求的 options 中定义:

const data = {
  html: '<p>I am a teapot</p><img src="https://secured-example-website.com/image.jpg">',
  css: 'p { color: red; }',
  options: {
    extra_http_headers: {
      authorization: 'Bearer <replace_with_your_auth_key>'
    }
  }
};

axios.post( 'exportpdf_service_url placeholder', data, config )
  .then( response => {
    fs.writeFileSync('./file.pdf', response.data, 'binary')
  }).catch( error => {
    console.log( error );
  });
在应用程序配置中和请求中定义的头部将被合并。如果同一头部在两个地方都定义了,则优先使用来自 PDF 选项的头部值,而不是来自应用程序配置的值。

SSL 通信

可以使用安全连接与 Export to PDF On-Premises 进行通信。为此,需要使用 SSL 证书设置负载均衡器,如 NGINX 或 HAProxy。

下面是 HAProxy 和 NGINX 的配置示例。

HAProxy 示例

这是一个基本的 HAProxy 配置:

global
  daemon
  maxconn 256
  tune.ssl.default-dh-param 2048

defaults
  mode http
  timeout connect 5000ms
  timeout client 50000ms
  timeout server 50000ms

frontend http-in
  bind *:80
  bind *:443 ssl crt /etc/ssl/your_certificate.pem
  http-request set-header X-Forwarded-Proto https if { ssl_fc }
  http-request set-header X-Forwarded-Proto http if !{ ssl_fc }
  redirect scheme https if !{ ssl_fc }

  default_backend servers

backend servers
  server server1 127.0.0.1:8080 maxconn 32

NGINX 示例

这是一个基本的 NGINX 配置:

events {
  worker_connections  1024;
}

http {
  server {
    server_name your.domain.name;

    listen 443;
    ssl on;
    ssl_certificate /etc/ssl/your_cert.crt;
    ssl_certificate_key /etc/ssl/your_cert_key.key;

    location / {
      proxy_pass http://127.0.0.1:8080;

      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "Upgrade";
      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_http_version 1.1;
    }
  }
}

Docker 镜像不包含内置的 SSL 配置。SSL 必须由反向代理处理,该代理将请求转发到容器在 8080 端口上的 HTTP 服务。

日志

Export to PDF On-Premises 的日志写入 stdout 和 stderr。大多数日志格式为 JSON。它们可用于监控或调试目的。在生产环境中,建议将日志存储到文件中或使用分布式日志系统(如 ELK 或 CloudWatch)。

使用日志监控 Export to PDF

为了更深入地了解 Export to PDF On-Premises 的性能表现,可以使用日志进行监控。要启用此功能,请添加 ENABLE_METRIC_LOGS=true 环境变量。

日志结构

日志结构包含以下信息:

  • handler:操作的统一标识符。使用此字段来识别调用。

  • traceId:唯一的 RPC 调用 ID。

  • tags:以分号分隔的标签列表。使用此字段过滤指标日志。

  • data:包含额外信息的对象。它可能因不同的传输方式而异。

  • data.duration:请求持续时间(毫秒)。

  • data.transport:请求传输的类型。可能是 http 或 ws (websocket)。

  • data.status:请求状态。可以是 success、fail 或 warning。

  • data.statusCode:HTTP 状态码标准中的响应状态。

此外,对于 HTTP 传输,还包括以下信息:

  • data.url:URL 路径。

  • data.method:请求方法。

如果发生错误,data.status 将为 failed,且 data.message 将包含错误消息。

HTTP 传输的日志示例:

{
  "level": 30,
  "time": "2021-03-09T11:15:09.154Z",
  "msg": "Request summary",
  "handler": "convertHtmlToPdf",
  "traceId": "85f13d92-57df-4b3b-98bb-0ca41a5ae601",
  "data": {
    "duration": 2470,
    "transport": "http",
    "statusCode": 200,
    "status": "success",
    "url": "/v1/convert",
    "method": "POST"
  },
  "tags": "metrics"
}

Docker

Docker 具有内置的日志记录机制,可捕获容器输出的日志。默认日志驱动程序将日志写入文件。

使用该驱动程序时,使用 docker logs 命令显示容器的日志。可以添加 -f 标志以实时查看日志。有关日志命令的更多信息,请参阅 官方 Docker 文档。

当容器长时间运行时,日志可能会占用大量空间。为避免此问题,请确保启用日志轮转。这可以通过 max-size 选项设置。

分布式日志

如果运行多个 Export to PDF On-Premises 实例,建议使用分布式日志系统。它允许在一个地方查看和分析所有实例的日志。

AWS CloudWatch 和其他云解决方案

如果在云中运行 Export to PDF On-Premises,最简单且推荐的方法是使用所选提供商提供的服务。

以下是一些可用的服务:

要在 AWS ECS 中使用 CloudWatch,必须预先创建日志组,并将日志驱动程序更改为 awslogs。当日志驱动程序配置正确后,日志将直接流式传输到 CloudWatch。

logConfiguration 可能如下所示:

"logConfiguration": {
  "logDriver": "awslogs",
  "options": {
    "awslogs-region": "us-west-2",
    "awslogs-group": "tinysource",
    "awslogs-stream-prefix": "tiny-pdf-converter-logs"
  }
}

有关更多信息,请参阅 使用 awslogs 日志驱动程序 文章。

本地化解决方案

如果使用特定的基础设施(如自有环境)或因某些原因无法使用提供商提供的服务,可以使用一些本地化分布式日志系统。

有许多可用的解决方案,包括:

这是基于 Elasticsearch、Logstash 和 Kibana 构建的堆栈。在此配置中,Elasticsearch 存储日志,Filebeat 从 Docker 读取日志并将其发送到 Elasticsearch,而 Kibana 用于查看它们。由于日志已经是结构化数据,因此不需要 Logstash。

它使用专用的 Docker 日志驱动程序 发送日志。它具有内置的前端,但也可以与 Elasticsearch 和 Kibana 集成以实现更好的过滤。

它使用专用的 Docker 日志驱动程序发送日志。它具有内置的前端,还需要 Elasticsearch 来存储日志以及 MongoDB 数据库来存储配置。

配置示例

示例配置使用 Fluentd、Elasticsearch 和 Kibana 从 Docker 捕获日志。

在运行 Export to PDF On-Premises 之前,请先准备日志服务。为了本示例的目的,使用 Docker Compose。在 docker-compose.yml 文件中创建 fluentd、elasticsearch 和 kibana 服务:

version: '3.7'
services:
  fluentd:
    build: ./fluentd
    volumes:
      - ./fluentd/fluent.conf:/fluentd/etc/fluent.conf
    ports:
      - "24224:24224"
      - "24224:24224/udp"

  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:6.8.5
    expose:
      - 9200
    ports:
      - "9200:9200"

  kibana:
    image: docker.elastic.co/kibana/kibana:6.8.5
    environment:
      ELASTICSEARCH_HOSTS: "http://elasticsearch:9200"
    ports:
      - "5601:5601"

要将 Fluentd 与 Elasticsearch 集成,首先需要在 Fluentd 镜像中安装 fluent-plugin-elasticsearch。为此,创建一个名为 fluentd/Dockerfile 的文件,内容如下:

FROM fluent/fluentd:v1.10-1

USER root

RUN apk add --no-cache --update build-base ruby-dev \
  && gem install fluent-plugin-elasticsearch \
  && gem sources --clear-all

接下来,在 fluentd/fluent.conf 文件中配置输入服务器和到 Elasticsearch 的连接:

<source>
  @type forward
  port 24224
  bind 0.0.0.0
</source>
<match *.**>
  @type copy
  <store>
    @type elasticsearch
    host elasticsearch
    port 9200
    logstash_format true
    logstash_prefix fluentd
    logstash_dateformat %Y%m%d
    include_tag_key true
    type_name access_log
    tag_key @log_name
    flush_interval 1s
  </store>
  <store>
    @type stdout
  </store>
</match>

现在服务已准备好运行:

docker-compose up --build

当服务就绪后,启动 Export to PDF On-Premises。

docker run --init -p 8080:8080 \
--log-driver=fluentd \
--log-opt fluentd-address=[Fluentd address]:24224 \
[Your config here] \
registry.containers.tiny.cloud/pdf-converter-tiny:[version]
  • 在浏览器中打开 Kibana。

  • 在首次运行时,可能会被要求创建索引。

  • 使用 fluentd-* 模式并按“Create"按钮。

  • 完成此步骤后,日志应出现在“Discover"标签页中。