Рейтинг:0

Как опубликовать PDF?

флаг km

Я выполнил следующие шаги, чтобы опубликовать файл PDF в Drupal.

  1. Включите JSON API для создания в admin/config/services/jsonapi.

  2. Включить медиа-ресурс POST

    Медиа /media/{media}/edit: ПОЛУЧИТЬ, ИСПРАВИТЬ, УДАЛИТЬ
          /entity/media: POST
    
    Методы: POST, форматы: json: аутентификация: cookie
    
  3. Создайте приложение Angular и вставьте его на страницу Drupal в виде блока.

Приложение Angular захватывает страницу с помощью jspdf и встраивает изображение в PDF. Вместо использования перехватчика я получаю токен с каждым запросом.

this.certificateService.getCsrf().subscribe(токен => {
  this.certificateService.uploadMedia(pdf.output('blob'), fileName, token).subscribe({
    завершено: () => {
      console.log('размещенные медиафайлы');
    }
  })
});

получитьCsrf() захватывает токен в виде текста.

getCsrf(): Наблюдаемый<строка> {
  const headers = new HttpHeaders().set('Content-Type', 'text/plain; charset=utf-8');

  вернуть this.httpClient.get(this.host + '/session/token', {заголовки: заголовки, responseType: 'text'}).pipe(catchError(this.handleError<any>('token')))
}

загрузитьМедиа() пытается опубликовать файл PDF на носителе в Drupal.

uploadMedia(pdf: Blob, name: string, token: string): Observable<any> {
  const formData: FormData = new FormData();
  formData.append('сертификат', pdf, имя);
  константные заголовки = новые HttpHeaders();
  headers.set('Принять', 'application/vnd.api+json');
  headers.set('X-CSRF-токен', токен);
  // headers.set('Content-Type','application/octet-stream');
  headers.set('Content-Type','application/hal+json');
  headers.set('Content-Disposition',`file; filename=${name}`);

  вернуть this.httpClient.post(this.host + '/entity/media', formData, {headers: headers})
    .трубка(
      catchError(this.handleError<любой>('uploadMedia'))
    );
}

Ошибка, которую я получаю, 415 Неподдерживаемый тип носителя.

415 Неподдерживаемый тип носителя

Я использую Angular 13 и Drupal 9.

Я посмотрел журнал ошибок Drupal; он сообщает о следующем исключении.

Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException: не найден маршрут, соответствующий "Content-Type: multipart/form-data; border=----WebKitFormBoundaryYAzO5lNTfgLQwQq9" в Drupal\Core\Routing\ContentTypeHeaderMatcher->filter()

Просто установка заголовка Content-Type не всегда изменяет публикуемый заголовок типа контента. например Как с axios, так и с angular http, если вы публикуете Данные формы array, вы получите форму, состоящую из нескольких частей, даже если заголовок на уровне вызова является приложением/октетным потоком

Использование axios в angular следующим образом приводит к «application/octet-stream»:

импортировать Axios из 'axios-observable'; 
Axios.defaults.headers.post['X-CSRF-Token'] = токен;
вернуть Axios.post(this.host + '/entity/media', pdf, {
  заголовки: {
    Принять: `application/json, text/plain, */*',
    Авторизация: `Basic ${basic}`,
    Файл cookie: ${cookie}; XDEBUG_SESSION=13681',
    'Content-Type': 'application/octet-stream',
  }
});

Передача необработанных данных PDF приводит к «application/pdf»

константные заголовки = новые HttpHeaders();
headers.set('Content-Type', 'application/octet-stream');
вернуть this.httpClient.post(this.host + '/entity/media', pdf, {заголовки: заголовки})
  .трубка(
    catchError(this.handleError<любой>('uploadMedia'))
);

Просмотр страницы остальных услуг админ/конфиг/сервисы/отдых, допустимый формат содержимого — json.

Отладка подтверждает, что Symfony проверяет это значение

Symfony принимает JSON

Попытка интерфейса REST, т.е. '/jsonapi/media/document/field_media_document/'

Да, в файле web/core/modules/file/src/Plugin/rest/resource/FileUploadResource.php есть требование типа содержимого «bin», которое

// Добавляем проверку доступа к формату типа контента. Это обеспечит соблюдение всех
// входящие запросы могут использовать только 'application/octet-stream'
// Заголовок Content-Type.

/объект/медиа URL-адрес запроса JSON API требует запроса JSON в соответствии с web/core/lib/Drupal/Core/Routing/ContentTypeHeaderMatcher.php

JSON-запрос объекта мультимедиа

Рейтинг:0
флаг cn

Я использую Angular, а не React, но я уверен, что эта часть неверна:

  // headers.set('Content-Type','application/octet-stream');
  headers.set('Content-Type','application/hal+json');

Файлы должны быть размещены как приложение/октетный поток. Это не объект JSON; это файл.

Кроме того, вам может понадобиться преобразовать данные PDF во что-то, что понимает JSON:API. Например, вот документы, как сделать это с помощью axios/Node.js.

В моем случае для файлов изображений мне пришлось прочитать файл как большой двоичный объект (код React, но я могу привести пример):

// https://stackoverflow.com/a/46568146
функция readFileBlob (fileBlob: Blob) {
  вернуть новое обещание ((разрешить) => {
    const reader = новый FileReader();
    reader.onload = () => {
      разрешить (читатель.результат);
    };
    reader.onabort = () => Promise.reject(Ошибка('чтение файла было прервано'));
    reader.onerror = () => Promise.reject(Error('Ошибка чтения файла'));
    читатель.readAsArrayBuffer(fileBlob);
  });
}

// fileToPost — это строка, содержащая блоб:
// блоб:http://localhost:8100/00507d3e-7f6f-4f48-be80-b55c8bc20dd3
константа postAuthFileBlob = асинхронная (
  fetchUrl: строка,
  fileToPost: строка,
  // Fetch может вернуть что угодно.
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
): Обещание <любое> => {
  const fileBlob = await fetch(fileToPost).then((res) => res.blob());
  const arrayStr = (ожидание чтенияFileBlob(fileBlob)) as ArrayBuffer;
  вернуть postAuthFileBlobPart2 (fetchUrl, arrayStr);
};
Interlated avatar
флаг km
Я думаю, вы близки. Серверная часть жалуется, что тип содержимого является multipart/form-data вместо application/octet-stream.
Interlated avatar
флаг km
Просто отправка pdf дает application/pdf return this.httpClient.post(this.host + '/entity/media', pdf, {headers: headers}). По-прежнему drupal не может найти соответствие для application/pdf. Не найден маршрут, соответствующий «Content-Type: application/pdf» в Drupal\Core\Routing\ContentTypeHeaderMatcher->filter() (строка 49 из
флаг cn
@Interlated Как я уже говорил, вам нужно публиковать как `application/octet-stream`. По какой-то причине вы закомментировали это в своем коде, но вы должны опубликовать как `application/octet-stream`, если хотите загрузить какие-либо двоичные файлы.

Ответить или комментировать

Большинство людей не понимают, что склонность к познанию нового открывает путь к обучению и улучшает межличностные связи. В исследованиях Элисон, например, хотя люди могли точно вспомнить, сколько вопросов было задано в их разговорах, они не чувствовали интуитивно связи между вопросами и симпатиями. В четырех исследованиях, в которых участники сами участвовали в разговорах или читали стенограммы чужих разговоров, люди, как правило, не осознавали, что задаваемый вопрос повлияет — или повлиял — на уровень дружбы между собеседниками.