двоичные ответы с Serverless, Bref PHP и Slim с кодировкой CORS или base64
Я настраивал бессерверную (.com) установку с AWS, используя Bref (уровень PHP) для запуска MPDF для преобразования HTML в PDF с помощью AWS Lambda и API Gateway. Следуя инструкциям,.. вот настройка.
После долгой отладки выяснилось, что я могу:
Добавить
apiGateway
вариант в бессерверном файле, но я всегда возникает проблема CORS (т. е. классическийNo 'Access-Control-Allow-Origin' header is present
). Я пробовал каждую комбинацию заголовков со стороны клиента / запроса и ответов со стороны сервера (см. Код ниже).ИЛИ, я не могу
apiGateway
вариант, как показано ниже, но тогда у меня есть to base64encode my body (see$body = base64_encode($pdf);
) или я получаю сообщение об ошибке BrefThe Lambda response cannot be encoded to JSON (...)
говоря, что нужно использоватьapiGateway
параметры.
Encoding the body is fine, but doesn't work well for direct download as I need to base64decode the data
from the response in order to have the binary data.
Help.
serverless.yml: (notice the commented out apiGateway settings - read more for why)
service: html2pdf
provider:
name: aws
region: us-east-1
runtime: provided
stage: ${opt:stage, 'dev'}
# apiGateway: ## <======= We talk about this below
# binaryMediaTypes:
# - '*/*'
# environment:
# BREF_BINARY_RESPONSES: 1
plugins:
- ./vendor/bref/bref
functions:
html2pdf:
handler: index.php
description: ''
timeout: 28 # in seconds (API Gateway has a timeout of 29 seconds)
layers:
- ${bref:layer.php-73-fpm} #-fpm
events:
- http:
path: /html2pdf
method: post
cors: true
# Exclude files from deployment
package:
exclude:
- 'node_modules/**'
- 'tests/**'
The index.php (mentioned in the yml file above):
<?php
require_once __DIR__ . '/../vendor/autoload.php';
use App\JsonParserMiddleware;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
$app = AppFactory::create();
$app->addMiddleware(new JsonParserMiddleware());
$app->post("/html2pdf", function (Request $request, Response $response) {
$data = $request->getParsedBody();
$payload = [];
$statusCode = 200;
if ($data['data'] == null) {
$payload['error'] = "HTML 64-bit encoded string is required";
return response($response, $payload, 422);
}
$mpdf = new \Mpdf\Mpdf(['tempDir' => '/tmp']);
$mpdf->WriteHTML(base64_decode($data['data']));
$pdf = $mpdf->Output(null,"S");
$filename = $data['title'];
$body = base64_encode($pdf);
$response->getBody()->write($body);
$response->isBase64Encoded = true;
$response = $response
->withHeader("Access-Control-Allow-Origin", "*")
->withHeader('Access-Control-Allow-Credentials', "true")
->withHeader('Content-Type','application/pdf')
->withHeader('Content-Disposition', sprintf('attachment; filename="%s"', $filename))
->withStatus($statusCode);
return $response;
});
And the client-side code, using axios, is:
let data = { data: <<some base64 encoded html string>>, title: "file.pdf" };
let options = {
headers: {
"Content-Type": "application/json",
// "Accept": "*/*",
},
}
let payload = {data : btoa(data),title:"contract.pdf"};
let url = "https://oli9w0wghb.execute-api.us-east-1.amazonaws.com/dev/html2pdf";
axios.post(url, payload, options)
.then(response => {
console.log(response.data);
});
1 ответ
Привет, у меня была такая же проблема, и я ее исправил:
Заголовки, которые я использовал в контроллере (я использую SLIM4):
$response->getBody()->write($pdfContent);
$response = $response->withHeader('Content-type', 'application/pdf');
$response->isBase64Encoded = true;
Затем, чтобы настроить serverless.yml, мне нужно добавить:
service: *****
provider:
region: ****
runtime: ***
profile: ****
apiGateway:
binaryMediaTypes:
- 'application/pdf'
environment:
BREF_BINARY_RESPONSES: '1'
plugins:
- ./vendor/bref/bref
functions:
api:
handler: public/index.php
description: ''
timeout: 28 # in seconds (API Gateway has a timeout of 29 seconds)
layers:
- ${bref:layer.php-81-fpm}
events:
- http: ANY /{proxy+}
environment:
BREF_BINARY_RESPONSE: '1'
Я надеюсь, это поможет вам.