В вашей реализации есть как минимум две проблемы:
- Ваш перевод с
CURL -X PUT
на TIdHTTP
неверен. - Вы не указали
Accept
HTTP заголовок для извлечения извлеченного текста в указанном c формате.
Как перевести curl -X PUT
в Indy?
Сначала давайте проясним, что curl -X PUT --data-binary @<filename> <url>
является то же самое, что curl -T <filename> <url>
, когда:
<url>
Схема HTTP
или HTTPS
<url>
не заканчивается /
Поэтому использование одного или другого не должно иметь значения в вашем случае. См. Также документация по curl .
Во-вторых, TIdMultiPartFormDataStream
предназначен для использования с глаголом POST
, однако ничто не может помешать вам передать его в TIdHTTP.Put
, поскольку он получен косвенно от TStream. Даже существует выделенный инвариант метода TIdHTTP.Post
, который принимает TIdMultiPartFormDataStream
:
Функция Post (AURL: строка; ASource: TIdMultiPartFormDataStream): строка; overload;
Чтобы загрузить файл в службу, просто используйте метод TIdHTTP.Put
с TFileStream
в качестве аргумента, указав правильный тип содержимого файла, загружаемого в заголовок HTTP.
И, наконец, вы пытаетесь извлечь простой текст из документа, но вы не указали тип контента, который должен возвращать сервис. Это делается через HTTP-заголовок Accept
. Экземпляр по умолчанию TIdHTTP
имеет свойство IdHTTP.Request.Accept
, инициализированное 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
(это может варьироваться в зависимости от версии Indy). Поэтому по умолчанию Тика вернет HTML форматированный текст. Чтобы получить простой текст, вы должны изменить его на 'text/plain; charset=utf-8'
.
Исправлена реализация:
uses IdGlobal, IdHTTP;
function GetDocumentText(const FileName, ContentType: string): string;
var
IdHTTP: TIdHTTP;
Stream: TIdReadFileExclusiveStream;
begin
IdHTTP := TIdHTTP.Create;
try
IdHTTP.Request.Accept := 'text/plain; charset=utf-8';
IdHTTP.Request.ContentType := ContentType;
Stream := TIdReadFileExclusiveStream.Create(FileName);
try
Result := IdHTTP.Put('http://localhost:9998/tika', Stream);
finally
Stream.Free;
end;
finally
IdHTTP.Free;
end;
end;
function GetPDFText(const FileName: string): string;
const
PDFContentType = 'application/pdf';
begin
Result := GetDocumentText(FileName, PDFContentType);
end;
function GetDOCXText(const FileName: string): string;
const
DOCXContentType = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
begin
Result := GetDocumentText(FileName, DOCXContentType);
end;
Согласно документации Tika она также поддерживает публикацию данные из нескольких частей. Если вы настаиваете на использовании этого подхода, вам следует изменить целевой ресурс на /tika/form
и переключиться на метод Post
в своей реализации:
function GetDocumentText(const FileName, ContentType: string): string;
var
IdHTTP: TIdHTTP;
FormData: TIdMultiPartFormDataStream;
begin
IdHTTP := TIdHTTP.Create;
try
IdHTTP.Request.Accept := 'text/plain; charset=utf-8';
FormData := TIdMultiPartFormDataStream.Create;
try
FormData.AddFile('file', FileName, ContentType); { older Indy versions: FormData.Add(...) }
Result := IdHTTP.Post('http://localhost:9998/tika/form', FormData);
finally
FormData.Free;
end;
finally
IdHTTP.Free;
end;
end;
Почему исходная рассматриваемая реализация работает с файлами PDF ?
Когда вы Post
многочастные данные формы с помощью TIdHTTP
, Indy автоматически устанавливает тип содержимого запроса на 'multipart/form-data; boundary=...whatever...'
. Это не тот случай, когда вы Put
(если вы не установили его вручную перед выполнением запроса) и, следовательно, TIdHttp.Request.ContentType
остается пустым. Теперь я могу только догадываться, что когда Tika видит пустой тип контента, он возвращается к какому-либо типу по умолчанию, который может быть PDF, и все равно каким-то образом может читать документ из многокомпонентного запроса.