Datastream을 PDF 뷰어에 직접 제공하는 방법
23097 단어 beginnersjavascriptreactnextjs
약간의 맥락
이 프로젝트에서는 NextJS, MinIO(내 s3 버킷에 액세스하기 위해) 및 React PDF 뷰어를 사용하고 있습니다. API의 기본 설정에서 NextJS를 사용하고 있으므로 페이지에서 고유한 api 디렉토리를 사용하고 있습니다. 나는 그들이 백그라운드에서 진행하는 자동 매직 라우팅 시스템을 매우 좋아합니다. 이제 API에서 직접 데이터를 공급해야 하는 이유가 궁금할 것입니다. 이 프로젝트의 S3 버킷은 K8s(Kubernetes) 클러스터 내에서만 사용할 수 있도록 구성되었습니다. 즉, 브라우저가 외부에 있거나 클러스터에 있기 때문에 사전 서명된 URL을 사용하여 브라우저에서 문서를 가져올 수 없었습니다. 따라서 클러스터 내에서 데이터를 검색하는 방법이 필요했습니다. 이로 인해 API에서 직접 데이터를 제공하게 됩니다.
샘플 NextJS 구조
├─ app
├── components
├── lib <-- custom
│ ├── **/*.ts
│ ├── minio.ts
└── pages
├── api
│ ├──[documentId].ts
└── index.tsx
미니IO
MinIO JavaScript Client SDK으로 작업 중이므로 API에서 MinIO 연결을 만들 수 있습니다.
먼저 AWS S3 버킷에 연결하기 위해 환경 변수를 제공하는 클라이언트 정의와 내 앱에 필요한 메서드가 있는 MinIo 구성 파일을 설정했습니다.
import * as Minio from 'minio';
import config from 'lib/config';
import { Readable } from 'stream';
import { NextApiResponse } from 'next';
const { BUCKET_NAME, BUCKET_HOST, BUCKET_PORT, AWS_ACCESSKEY_ID, AWS_SECRET_ACCESS_KEY } = config;
export default function minio(): Minio.Client {
global.minio =
global.minio ||
new Minio.Client({
endPoint: BUCKET_HOST,
port: Number(BUCKET_PORT),
useSSL: false,
accessKey: AWS_ACCESSKEY_ID,
secretKey: AWS_SECRET_ACCESS_KEY,
});
return global.minio;
}
// Checks if Bucket exists, create bucket if it does not
export const upsertMinioBucket = async (minioClient: Minio.Client) => {
const bucketExists = await minioClient.bucketExists(BUCKET_NAME);
if (bucketExists) {
return true;
} else {
await minioClient.makeBucket(BUCKET_NAME, 'us-east-1');
return await minioClient.bucketExists(BUCKET_NAME);
}
};
// Upload file to bucket and returns with object => (err| objInfo)
// Uploads contents from a file to objectName.
// fPutObject(bucketName, objectName, filePath, metaData[, callback])
export const upsertMinioFile = async (minioClient: Minio.Client, filePath: string, fileName: string) => {
if (filePath) {
const objectMade = await minioClient.fPutObject(BUCKET_NAME, fileName, filePath, {});
return objectMade;
}
};
export const loadMinioStream = async (minioClient: Minio.Client, fileName: string | string[]) => {
const response = await minioClient.getObject(BUCKET_NAME, fileName).then((err, stream) => (!err ? stream : err));
return response;
};
export const streamToResponse = async (stream: Readable, res: NextApiResponse): Promise<any> => {
return new Promise<any>(() => {
stream.on('data', function (chunk) {
res.write(chunk);
});
stream.on('end', () => {
res.end();
});
stream.on('error', (err) => res.end(err));
});
};
getObject + streamToResponse = ❤️
API 경로
[documentId].ts
에서 MinIO 개체 작업getObject
과 스트림 데이터를 통해 실행하기 위한 사용자 지정 메서드를 사용하여 스트림을 응답에 직접 씁니다.import { NextApiRequest, NextApiResponse } from 'next';
import { runMiddleware } from 'lib/middleware';
import CORS from 'cors';
import minio, { loadMinioStream, streamToResponse, upsertMinioBucket } from 'lib/minio';
const client = minio();
// Initializing the cors middleware
const cors = runMiddleware(
CORS({
methods: ['GET', 'POST', 'OPTIONS'],
})
);
export default async function handler(_req: NextApiRequest, res: NextApiResponse) {
await cors(_req, res);
const { documentId = '1' } = _req.query;
const resp = await getDocumentStream(documentId, res);
res.json(resp);
}
export const getDocumentStream = async (documentId: string | string[], res: NextApiResponse) => {
try {
const exists = process.env.NODE_ENV !== 'test' ? await upsertMinioBucket(client) : false;
let resolve: any = null;
if (exists && process.env.NODE_ENV !== 'test') {
const stream = await loadMinioStream(client, documentId);
resolve = await streamToResponse(stream, res);
}
return {
statusCode: 200,
data: resolve,
};
} catch (e) {
return {
statusCode: 500,
data: {
success: false,
error: `${e}`,
},
};
}
};
React PDF 뷰어에 입력
그런 다음 내 파일을 PDF 뷰어에 표시하기 위해 내 API 경로를
fileURL
로 제공하고 Blam이 있습니다.export default function PDFViewer({ document}){
...
const [filePath, setFilePath] = useState('');
const workerUrl = 'https://unpkg.com/[email protected]/legacy/build/pdf.worker.js';
useEffect(() => {
if (document) {
let path = `//${window.location.hostname}${port}/api/documents/pdf/${document?.id}`;
const port = window.location.port == '80' ? '' : ':' + window.location.port;
setFilePath(path);
}
}, [document]);
}
return(
<Worker workerUrl={workerUrl}>
<Viewer fileUrl={filePath} />
</Worker>
)
참고: 이 특정 솔루션은 PDF에만 국한되지 않으며 이미지, 바이너리 등의 경우에 사용할 수 있습니다.
여기까지 왔다면 축하한다고 말하고 싶습니다! 당신은 끝까지 해냈습니다! 보상으로 이 gif를 선물합니다!
Reference
이 문제에 관하여(Datastream을 PDF 뷰어에 직접 제공하는 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/stories_of_ren/how-to-serve-your-datastream-directly-to-your-pdf-viewer-1nc텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)