[Integrering]{class="badge positive"}

Generera Experience Platform FPID:n med AEM Sites

[AEM Sites as a Cloud Service, AEM Sites 6.5]{class="badge informative"}

För integreringen av Adobe Experience Manager-webbplatser (AEM) som levereras via AEM Publish med Adobe Experience Platform (AEP) krävs att AEM genererar och underhåller en unik FPID-cookie för att unikt kunna spåra användaraktivitet.

FPID-cookien ska anges av servern (AEM Publish) i stället för att använda JavaScript för att skapa en cookie på klientsidan. Detta beror på att moderna webbläsare, som Safari och Firefox, kan blockera eller snabbt förfalla cookies som genererats av JavaScript.

Läs supportdokumentationen för att lära dig mer om hur första-delen-enhets-ID och Experience Cloud-ID fungerar tillsammans.

Nedan visas en översikt över hur FPID fungerar när du använder AEM som webbvärd.

FPID och ECID med AEM

Generera och behåll FPID med AEM

AEM Publish-tjänsten optimerar prestanda genom att cachelagra förfrågningar så många som möjligt, både i CDN- och AEM Dispatcher-cachen.

Det är en absolut nödvändighet att HTTP-begäranden som genererar FPID-cookie för en unik användare och returnerar FPID-värdet cachelagras aldrig, och skickas direkt från AEM Publish som kan implementera logik för att garantera unika funktioner.

Undvik att generera FPID-cookie för webbsidor eller andra tillgängliga resurser eftersom kombinationen av FPID:ts unika krav skulle göra dessa resurser otillgängliga.

I följande diagram beskrivs hur AEM Publish-tjänsten hanterar FPID:n.

FPID och AEM-flödesdiagram

  1. Webbläsaren begär en webbsida från AEM. Begäran kan behandlas med en cachelagrad kopia av webbsidan från CDN- eller AEM Dispatcher-cachen.
  2. Om webbsidan inte kan hanteras från cacheminnen i CDN eller AEM Dispatcher når förfrågan AEM Publish-tjänsten, som genererar den begärda webbsidan.
  3. Webbsidan skickas sedan tillbaka till webbläsaren och fyller i de cacheminnen som inte kunde hantera begäran. Med AEM förväntar du att antalet träffar i CDN och AEM Dispatcher ska vara över 90 %.
  4. Webbsidan innehåller JavaScript som gör en otillgänglig asynkron XHR-begäran (AJAX) till en anpassad FPID-server i AEM Publish-tjänsten. Eftersom detta är en otillgänglig begäran (på grund av dess slumpmässiga frågeparameter och Cache-Control-headers) cachelagras den aldrig av CDN eller AEM Dispatcher och når alltid AEM Publish-tjänsten för att generera svaret.
  5. Den anpassade FPID-servern i AEM Publish-tjänsten bearbetar begäran och genererar ett nytt FPID när ingen befintlig FPID-cookie hittas, eller förlänger livscykeln för en befintlig FPID-cookie. Servern returnerar också FPID i svarstexten som ska användas av JavaScript på klientsidan. Lyckligtvis är den anpassade FPID-serverlogiken liten, vilket förhindrar att den här begäran påverkar AEM Publish-tjänstens prestanda.
  6. Svaret på XHR-begäran återgår till webbläsaren med FPID-cookien och FPID som JSON i svarstexten för användning av Platform Web SDK.

Kodexempel

Följande kod och konfiguration kan distribueras till AEM Publish-tjänsten för att skapa en slutpunkt som genererar eller förlänger livscykeln för en befintlig FPID-cookie och returnerar FPID som JSON.

En AEM Publish HTTP-slutpunkt måste skapas för att en FPID-cookie ska kunna genereras eller utökas med en Sling-server.

  • Servern är bunden till /bin/aem/fpid eftersom autentisering inte krävs för att komma åt den. Om autentisering krävs binder du till en Sling-resurstyp.
  • Servern accepterar HTTP GET-begäranden. Svaret har markerats med Cache-Control: no-store för att förhindra cachelagring, men den här slutpunkten ska också begäras med unika frågeparametrar för cachebuffring.

När en HTTP-begäran når servern kontrollerar servern om det finns en FPID-cookie på begäran:

  • Om det finns en FPID-cookie förlänger du cookie-filens livslängd och samlar in dess värde för att skriva till svaret.
  • Om det inte finns någon FPID-cookie skapar du en ny FPID-cookie och sparar värdet för att skriva till svaret.

Servern skriver sedan FPID till svaret som ett JSON-objekt i formatet: { fpid: "<FPID VALUE>" }.

Det är viktigt att tillhandahålla FPID till klienten i brödtexten eftersom FPID-cookien är markerad som HttpOnly, vilket innebär att bara servern kan läsa dess värde, och inte JavaScript på klientsidan. För att undvika att FPID uppdateras i onödan vid varje sidinläsning ställs även en FPID_CLIENT-cookie in, vilket anger att FPID har genererats och att värdet exponeras för klientsidans JavaScript för användning.

FPID-värdet används för att parametrisera anrop med Platform Web SDK.

Nedan visas exempelkod för en AEM-serverslutpunkt (tillgänglig via HTTP GET /bin/aep/fpid) som genererar eller uppdaterar en FPID-cookie och returnerar FPID som JSON.

  • core/src/main/java/com/adobe/aem/guides/wkndexamples/core/aep/impl/FpidServlet.java
package com.adobe.aem.guides.wkndexamples.core.aep.impl;

import com.google.gson.JsonObject;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.Servlet;
import javax.servlet.http.Cookie;
import java.io.IOException;
import java.util.UUID;

import static org.apache.sling.api.servlets.ServletResolverConstants.SLING_SERVLET_PATHS;
import static org.apache.sling.api.servlets.ServletResolverConstants.SLING_SERVLET_METHODS;

@Component(
        service = {Servlet.class},
        property = {
                SLING_SERVLET_PATHS + "=/bin/aep/fpid",
                SLING_SERVLET_METHODS + "=GET"
        }
)
public class FpidServlet extends SlingAllMethodsServlet {
    private static final Logger log = LoggerFactory.getLogger(FpidServlet.class);
    private static final String COOKIE_NAME = "FPID";
    private static final String CLIENT_COOKIE_NAME = "FPID_CLIENT";
    private static final String COOKIE_PATH = "/";
    private static final int COOKIE_MAX_AGE = 60 * 60 * 24 * 30 * 13; // 13 months
    private static final String JSON_KEY = "fpid";

    @Override
    protected final void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws IOException {
        // Try to get an existing FPID cookie, this will give us the user's current FPID if it exists
        final Cookie existingCookie = request.getCookie(COOKIE_NAME);

        String cookieValue;

        if (existingCookie == null) {
            //  If no FPID cookie exists, create a new FPID UUID
            cookieValue = UUID.randomUUID().toString();
        } else {
            // If a FPID cookie exists, get its FPID UUID so its life can be extended
            cookieValue = existingCookie.getValue();
        }

        // Add the FPID value to the response, either newly generated or the extended one
        // This can be read by the Server (AEM Publish) due to HttpOnly flag.
        response.addHeader("Set-Cookie",
                COOKIE_NAME + "=" + cookieValue + "; " +
                        "Max-Age=" + COOKIE_MAX_AGE + "; " +
                        "Path=" + COOKIE_PATH + "; " +
                        "HttpOnly; " +
                        "Secure; " +
                        "SameSite=Lax");

        // Also set FPID_CLIENT cookie to avoid further server-side FPID generation
        // This can be read by the client-side JavaScript to check if FPID is already generated
        // or if it needs to be requested from server (AEM Publish)
        response.addHeader("Set-Cookie",
                CLIENT_COOKIE_NAME + "=" + cookieValue + "; " +
                        "Max-Age=" + COOKIE_MAX_AGE + "; " +
                        "Path=" + COOKIE_PATH + "; " +
                        "Secure; " +
                        "SameSite=Lax");

        // Avoid caching the response
        response.addHeader("Cache-Control", "no-store");

        // Return FPID in the response as JSON for client-side access
        final JsonObject json = new JsonObject();
        json.addProperty(JSON_KEY, cookieValue);

        response.setContentType("application/json");
        response.getWriter().write(json.toString());

HTML script

En anpassad klientsidesbaserad JavaScript måste läggas till på sidan för att anropa servern asynkront, generera eller uppdatera FPID-cookien och returnera FPID i svaret.

Det här JavaScript-skriptet läggs vanligtvis till på sidan på något av följande sätt:

XHR-anropet till den anpassade AEM FPID-servern är snabbt, även om det är asynkront, så det är möjligt för en användare att besöka en webbsida som hanteras av AEM och navigera bort innan begäran kan slutföras.
Om detta inträffar kommer samma process att försöka igen vid nästa sidinläsning av en webbsida från AEM.

HTTP-GET till AEM FPID-servern (/bin/aep/fpid) parametriseras med en slumpmässig frågeparameter för att säkerställa att ingen infrastruktur mellan webbläsaren och AEM Publish-tjänsten cachelagrar svaret från begäran.
På samma sätt läggs begärandehuvudet Cache-Control: no-store till för att det ska gå att undvika cachelagring.

När AEM FPID-servern anropas hämtas FPID från JSON-svaret och används av Platform Web SDK för att skicka det till Experience Platform API:er.

Mer information om hur du använder FPID:n i identityMap finns i dokumentationen för Experience Platform 1.

...
<script>
    // Wrap in anonymous function to avoid global scope pollution

    (function() {
        // Utility function to get a cookie value by name
        function getCookie(name) {
            const value = `; ${document.cookie}`;
            const parts = value.split(`; ${name}=`);
            if (parts.length === 2) return parts.pop().split(';').shift();
        }

        // Async function to handle getting the FPID via fetching from AEM, or reading an existing FPID_CLIENT cookie
        async function getFpid() {
            let fpid = getCookie('FPID_CLIENT');

            // If FPID can be retrieved from FPID_CLIENT then skip fetching FPID from server
            if (!fpid) {
                // Fetch FPID from the server if no FPID_CLIENT cookie value is present
                try {
                    const response = await fetch(`/bin/aep/fpid?_=${new Date().getTime() + '' + Math.random()}`, {
                        method: 'GET',
                        headers: {
                            'Cache-Control': 'no-store'
                        }
                    });
                    const data = await response.json();
                    fpid = data.fpid;
                } catch (error) {
                    console.error('Error fetching FPID:', error);
                }
            }

            console.log('My FPID is: ', fpid);
            return fpid;
        }

        // Invoke the async function to fetch or skip FPID
        const fpid = await getFpid();

        // Add the fpid to the identityMap in the Platform Web SDK
        // and/or send to AEP via AEP tags or direct AEP Web SDK calls (alloy.js)
    })();
</script>

Dispatcher allow, filter

Slutligen måste HTTP GET-begäranden till den anpassade FPID-servern tillåtas via konfigurationen för AEM Dispatcher filter.any.

Om den här Dispatcher-konfigurationen inte implementeras korrekt resulterar HTTP GET-begäranden till /bin/aep/fpid i 404.

  • dispatcher/src/conf.dispatcher.d/filters/filters.any
/1099 { /type "allow" /method "GET" /url "/bin/aep/fpid" }

Experience Platform-resurser

Läs följande Experience Platform-dokumentation för FPID (First-party device ID) och hantering av identitetsdata med Platform Web SDK.

recommendation-more-help
bb44cebf-d964-4e3c-b64e-ce882243fe4d