Last active
December 25, 2024 21:07
-
-
Save duongphuhiep/a3ed34c7bbd49199337a234e7b48a0d5 to your computer and use it in GitHub Desktop.
Revisions
-
duongphuhiep revised this gist
Feb 25, 2023 . 1 changed file with 40 additions and 38 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -14,52 +14,54 @@ I will resume the technique by some codes snippets and at the same time add the ```typescript /** * Send the request Cross-Origin and wait for a response * @param targetWindow: the window we want to broadcast the request to (usually `parent` or `iframe.contentWindow`) * @param request * @param timeoutMs: default 10000 * @param targetOrigin: default '*' * @returns promise on response */ export function requestCrossOrigin<TRequest, TResponse>( targetWindow: Window, request: TRequest, timeoutMs?: number, targetOrigin?: string ): Promise<TResponse> { //apply this https://advancedweb.hu/how-to-use-async-await-with-postmessage/ const mainPromise = new Promise<TResponse>((res, rej) => { const channel = new MessageChannel(); //setup listener to the response channel.port1.onmessage = ({ data }) => { channel.port1.close(); const response = data as TResponse | Error; if (response instanceof Error) { rej(response); } else { res(response); } }; targetOrigin = targetOrigin ?? '*'; //send the request targetWindow.postMessage(request, targetOrigin, [channel.port2]); }); if (!timeoutMs || timeoutMs < 0) timeoutMs = 10000; return Promise.race([ mainPromise, new Promise<TResponse>((_, reject) => setTimeout( () => reject( new Error( `Timeout: Unable to get response within ${timeoutMs} ms` ) ), timeoutMs ) ), ]); } /** @@ -70,6 +72,6 @@ export function requestCrossOrigin<TRequest, TResponse>( * @param response the response you want to send back */ export function replyCrossOrigin<TRequest, TResponse>(event: MessageEvent<TRequest>, response: TResponse | Error) { event.ports[0].postMessage(response); } ``` -
duongphuhiep revised this gist
Feb 25, 2023 . 1 changed file with 2 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -11,6 +11,7 @@ I will resume the technique by some codes snippets and at the same time add the # Codes snippets ```typescript /** * Send the request Cross-Origin and wait for a response * @param request @@ -71,3 +72,4 @@ export function requestCrossOrigin<TRequest, TResponse>( export function replyCrossOrigin<TRequest, TResponse>(event: MessageEvent<TRequest>, response: TResponse | Error) { event.ports[0].postMessage(response); } ``` -
duongphuhiep revised this gist
Feb 25, 2023 . 1 changed file with 54 additions and 55 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -11,64 +11,63 @@ I will resume the technique by some codes snippets and at the same time add the # Codes snippets /** * Send the request Cross-Origin and wait for a response * @param request * @param timeoutMs default 10000 * @param targetOrigin default '*' * @returns promise on response */ export function requestCrossOrigin<TRequest, TResponse>( request: TRequest, timeoutMs?: number, targetOrigin?: string ): Promise<TResponse> { //apply this https://advancedweb.hu/how-to-use-async-await-with-postmessage/ const mainPromise = new Promise<TResponse>((res, rej) => { const channel = new MessageChannel(); //setup listener to the response channel.port1.onmessage = ({ data }) => { channel.port1.close(); const response = data as TResponse | Error; if (response instanceof Error) { rej(response); } else { res(response); } }; targetOrigin = targetOrigin ?? '*'; //send the request parent.postMessage(request, targetOrigin, [channel.port2]); }); if (!timeoutMs || timeoutMs < 0) timeoutMs = 10000; return Promise.race([ mainPromise, new Promise<TResponse>((_, reject) => setTimeout( () => reject( new Error( `Timeout: Unable to get response within ${timeoutMs} ms` ) ), timeoutMs ) ), ]); } /** * Send response for requests coming from the requestCrossOrigin() function. * It is recommended to verify the `event.origin` before calling this function to make sure that the origin of the request is authorized. * For eg: `window.addEventListener('message', (event) => { if (event.origin==="https://myapp.com") replyCrossOrigin(event, myResponse) })`; * @param event the event object when the request is coming * @param response the response you want to send back */ export function replyCrossOrigin<TRequest, TResponse>(event: MessageEvent<TRequest>, response: TResponse | Error) { event.ports[0].postMessage(response); } -
duongphuhiep created this gist
Feb 11, 2023 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,74 @@ # Problem Your HTML page (the host page) has an Iframe. The Iframe source is on other domain, so you will have to use the `window.postMessage()` for cross-origin communication. But this communication is only in 1 direction (The Iframe can inform the Host or the Host can inform the Iframe) [This article](https://advancedweb.hu/how-to-use-async-await-with-postmessage/) shows you how to make the Request/Reply communication using `postMessage()` and `MessageChannel` combination. The article did not show you how to add a timeout to the communication, so the Iframe might wait forever if the Host did not response. I will resume the technique by some codes snippets and at the same time add the missing timeout implementation. # Codes snippets In this example: * the Iframe want to ask the Host a `IframeConfig` object, * the Iframe open a new `MessageChannel` to post a `IframeConfigRequest` object to the Host. * when the Host received this `IframeConfigRequest`, it will reply the `IframeConfig` object on the `MessageChannel` * we want the Promise<IframeConfig> to be terminated in timeout if the host did not response, so we make it race with a "timeout" promise. => what ever terminate first will solve the promise. ### Iframe codes ```typescript function requestIframeConfig(uuid: string): Promise<IframeConfig> { const mainPromise = new Promise<IframeConfig>((res, rej) => { const channel = new MessageChannel(); //setup listener to the response channel.port1.onmessage = ({ data }) => { channel.port1.close(); const response = data as IframeConfig|Error if (response instanceof Error) { rej(response); } else if (!response.type) { rej(new Error(`Unable to get IframeConfig from the sdk. Invalid response: missing type`)) } else { res(response); } }; //send the request const request: IframeConfigRequest = { type: MessageType.IframeConfigRequest, uuid } parent.postMessage(request, "*", [channel.port2]) }); return Promise.race([ mainPromise, new Promise<IframeConfig>((_, reject) => setTimeout(() => reject(new Error('Timeout: Unable to get IframeConfig from the sdk within 10 seconds')), 10000) ) ]); } ``` ### Host codes ```typescript let iframeConfig: IframeConfig; window.addEventListener( "message", function (event: MessageEvent<IframeConfigRequest>) { if (event.data.type != MessageType.IframeConfigRequest) return; //received non-concerned event //response to the iframe event.ports[0].postMessage(iframeConfig); } ); ```