스크린샷 마이크로서비스 구축
17084 단어 microservicesvercelhaxtheweb
이 사용 사례/요구 사항은 웹 페이지를 원격으로 렌더링할 수 있는 서비스를 구축하는 다른 것보다 훨씬 까다로웠습니다(예상치 않게도 그렇습니다). 게시, 삭제 등의 변경 사항을 설명하기 위해 Twitter 및 다른 곳에서 스크린샷을 찍는 것이 뉴스 및 미디어 아울렛 사이에서 인기가 있기 때문에 이전에 이 개념을 실험한 적이 있습니다.
많은 성공을 향한 길을 따라 생각하는 단계
"스크린샷을 찍고 싶다"고 말했습니다. 그때 나는 생각했다..
이제 이러한 문제와 해결책을 조금 풀어 보겠습니다.
인형극이란 무엇이며 인형극이 되어야 하는 이유는 무엇입니까?
Puppeteer은 사실상 헤드리스 브라우저 러너입니다. 그들은 "브라우저에서 수동으로 할 수 있는 대부분의 작업은 Puppeteer를 사용하여 수행할 수 있습니다!"라고 말합니다.
브라우저를 열고, URL을 입력하고, 로드되기를 기다리고, 스크롤하고, 무언가를 찾는 일련의 작업을 수행했다면 인형 조종자는 동일한 작업을 수행하기 위해 어떤 순서로 무엇을 해야 하는지 지시받을 수 있습니다. 웹사이트에는 많은 일반적인 사용 사례가 있습니다. 그 중 테스트 환경과 끌어오기 요청에서 CSS/레이아웃 변경을 알아차리는 데 널리 사용됩니다.
우리의 요구 사항은 미리 보기를 제공할 수 있도록 URL의 스크린샷을 찍어 웹 사이트 구축이 완료되었음을 효과적으로 나타내는 것이었습니다. 명확히 하자면, 작성 당시에는 잠시 추가될 예정이 아니므로 프로덕션 앱에 연결되지 않았지만 Vercel을 통해 이 문제를 해결할 수 있어 팀의 역량을 입증하는 데 도움이 되었습니다.
코드 미
이전 세 엔드포인트와 유사한 접근 방식을 사용하여 스크린샷 서비스는 다음과 같습니다.
import { getBrowserInstance } from '../getBrowserInstance.js';
import { stdResponse, invalidRequest, stdPostBody } from "../requestHelpers.js";
// this requires its own service instance and can't live with the monorepo
// due to the size of the dependencies involved
export default async function handler(req, res) {
const body = stdPostBody(req);
const urlToCapture = body.urlToCapture;
// Perform URL validation
if (!urlToCapture || !urlToCapture.trim()) {
res = invalidRequest(res, 'enter a valid url');
}
else {
if (!urlToCapture.includes("https://")) {
// try to fake it
urlToCapture = `https://${urlToCapture}`;
}
// capture options
var browserGoToOptions = {
timeout: 60000,
waitUntil: 'networkidle2',
};
var screenshotOptions = {
quality: body.quality ? parseInt(body.quality) : 75,
type: 'jpeg',
encoding: "base64"
};
var base64 = '';
let browser = null
try {
browser = await getBrowserInstance();
let page = await browser.newPage();
await page.goto(urlToCapture, browserGoToOptions);
// special support for isolating a tweet
if (urlToCapture.includes('twitter.com')) {
await page.waitForSelector("article[data-testid='tweet']");
const element = await page.$("article[data-testid='tweet']");
base64 = await element.screenshot(screenshotOptions);
}
else {
screenshotOptions.fullPage = true;
base64 = await page.screenshot(screenshotOptions);
}
res = stdResponse(res,
{
url: urlToCapture,
image: base64
}, {
methods: "GET,OPTIONS,PATCH,DELETE,POST,PUT",
cache: 1800
}
);
} catch (error) {
console.log(error)
res = invalidRequest(res, 'something went wrong', 500);
} finally {
if (browser !== null) {
await browser.close()
}
}
}
}
여기에서 "마법"은 아래에서 볼 수 있는 getBrowserInstance라는 것으로 롤업됩니다.
import chromium from 'chrome-aws-lambda'
export async function getBrowserInstance() {
const executablePath = await chromium.executablePath
if (!executablePath) {
// running locally
const puppeteer = await import('puppeteer').then((m) => {
return m.default;
});
return await puppeteer.launch({
args: chromium.args,
headless: true,
defaultViewport: {
width: 1280,
height: 720
},
ignoreHTTPSErrors: true
});
}
return await chromium.puppeteer.launch({
args: chromium.args,
defaultViewport: chromium.defaultViewport,
executablePath: executablePath,
headless: chromium.headless,
ignoreHTTPSErrors: true
});
}
이 간단한 기능은 프로덕션의 vercel(일명 Lambda 기반 호출)과 로컬vercel dev
호출(Chromium의 로컬 사본을 활용하여 렌더링 수행) 간의 차이를 수정하는 데 도움이 됩니다.
발생한 문제
프로덕션 환경에서 Vercel은 실행을 위해 컴파일할 수 있는 코드의 양만 허용합니다. 포함된 패키지의 크기 때문에 스크린샷 서비스는 모노 저장소에서 제거하고 독립 실행형으로 실행해야 했습니다. 이것은 이전 게시물에서 참조되었지만 미들웨어의 정의는 다음과 같습니다.
// screenshot - kept by itself bc of size of getBrowserInstance
MicroFrontendRegistry.add({
endpoint: "https://screenshoturl.elmsln.vercel.app/api/screenshotUrl",
name: "@core/screenshotUrl",
title: "Screenshot page",
description: "Takes screenshot of a URL and returns image",
params: {
urlToCapture: "full url with https",
quality: "Optional image quality parameter"
}
});
이것은 @core/screenshotUrl
호출을 매우 특정한 주소로 매핑합니다. 나는 URL 구조의 나머지 부분과 더 일치하는 것을 원하기 때문에 이 솔루션의 열렬한 팬은 아니지만 이것이 세상의 끝은 아닙니다.
동영상
다음은 코드가 원격 URL을 처리할 수 있는 방법과 트위터에서 트윗을 격리하는 기능을 지원하여 복잡성이 증가하는 방법을 설명하는 동안 스크린샷 도구의 데모입니다 💪.
Reference
이 문제에 관하여(스크린샷 마이크로서비스 구축), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/btopro/building-a-screenshot-microservice-2om8
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
import { getBrowserInstance } from '../getBrowserInstance.js';
import { stdResponse, invalidRequest, stdPostBody } from "../requestHelpers.js";
// this requires its own service instance and can't live with the monorepo
// due to the size of the dependencies involved
export default async function handler(req, res) {
const body = stdPostBody(req);
const urlToCapture = body.urlToCapture;
// Perform URL validation
if (!urlToCapture || !urlToCapture.trim()) {
res = invalidRequest(res, 'enter a valid url');
}
else {
if (!urlToCapture.includes("https://")) {
// try to fake it
urlToCapture = `https://${urlToCapture}`;
}
// capture options
var browserGoToOptions = {
timeout: 60000,
waitUntil: 'networkidle2',
};
var screenshotOptions = {
quality: body.quality ? parseInt(body.quality) : 75,
type: 'jpeg',
encoding: "base64"
};
var base64 = '';
let browser = null
try {
browser = await getBrowserInstance();
let page = await browser.newPage();
await page.goto(urlToCapture, browserGoToOptions);
// special support for isolating a tweet
if (urlToCapture.includes('twitter.com')) {
await page.waitForSelector("article[data-testid='tweet']");
const element = await page.$("article[data-testid='tweet']");
base64 = await element.screenshot(screenshotOptions);
}
else {
screenshotOptions.fullPage = true;
base64 = await page.screenshot(screenshotOptions);
}
res = stdResponse(res,
{
url: urlToCapture,
image: base64
}, {
methods: "GET,OPTIONS,PATCH,DELETE,POST,PUT",
cache: 1800
}
);
} catch (error) {
console.log(error)
res = invalidRequest(res, 'something went wrong', 500);
} finally {
if (browser !== null) {
await browser.close()
}
}
}
}
import chromium from 'chrome-aws-lambda'
export async function getBrowserInstance() {
const executablePath = await chromium.executablePath
if (!executablePath) {
// running locally
const puppeteer = await import('puppeteer').then((m) => {
return m.default;
});
return await puppeteer.launch({
args: chromium.args,
headless: true,
defaultViewport: {
width: 1280,
height: 720
},
ignoreHTTPSErrors: true
});
}
return await chromium.puppeteer.launch({
args: chromium.args,
defaultViewport: chromium.defaultViewport,
executablePath: executablePath,
headless: chromium.headless,
ignoreHTTPSErrors: true
});
}
// screenshot - kept by itself bc of size of getBrowserInstance
MicroFrontendRegistry.add({
endpoint: "https://screenshoturl.elmsln.vercel.app/api/screenshotUrl",
name: "@core/screenshotUrl",
title: "Screenshot page",
description: "Takes screenshot of a URL and returns image",
params: {
urlToCapture: "full url with https",
quality: "Optional image quality parameter"
}
});
다음은 코드가 원격 URL을 처리할 수 있는 방법과 트위터에서 트윗을 격리하는 기능을 지원하여 복잡성이 증가하는 방법을 설명하는 동안 스크린샷 도구의 데모입니다 💪.
Reference
이 문제에 관하여(스크린샷 마이크로서비스 구축), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/btopro/building-a-screenshot-microservice-2om8텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)