für facebook und Co
AngularJS App kompatibel machen

Das Problem: die Vorschau auf eine Angular View wird bei Facebook (oder G+ usw) nicht korrekt angezeigt.

So wollen wir einen Link zu einem Event bei Facebook teilen.

Die URL:

Frontpage-Neues-Design

Zeigt folgenden Inhalt:

angularjs_event_page

Das Resultat der Facebook Vorschau:
angularjs_page_not_working_on_fb

Die Erwartung wäre, dass das Event Titelbild angezeigt wird, sowie der Beschreibungstext.

Das ist jedoch nicht möglich, da die fertige Seite unserer AngularJS App erstmal gerendert werden muss, und zwar Clientseitig. Der FB Preview Modus führt dies eben einfach  nicht durch – ebenso wie andere Social Media anbieter auch. Es wird eine statische fertige Seite erwartet (zumindest zum jetzigen Zeitpunkt :-).

Die Lösung

Wir stellen eine URL bereit, die

  • in den sozialen Kanälen geteilt werden kann.
  • in jedem Browser aufgerufen werden kann.

 

Der Webserver entscheidet welchen Inhalt der Anfragende bekommen soll. Den Maschinen lesbaren, oder die Full-Blown Angular App für einen menschlichen User.

Achtung: Unser Vorgehen ist aus technischen Gründen nicht ganz die 100% Lösung – denn es ist nicht möglich, die URL aus der Browser Zeile zu teilen. Hier ist bei uns noch immer das Hashtag enthalten. Alles was hinter dem Hashtag steht, wird nicht an den Server gesendet. Somit kann keine Regel erkennen, dass es sich um einen Aufruf des Event Flyers für ein bestimmtes Event handelt. Es gibt dafür aber eine Lösung, aus technischen Gründen können wir die heute aber nicht einsetzen. Der Vollständigkeit halber sei es erwähnt: Man aktiviert den HTML5 Mode am locationProvider. Außerdem setzt man das Base-Tag.

Im Konfig Bereich den HTML5 Mode am location Provider aktivieren.

eventKeeper
        .config(
                function($stateProvider, $cookiesProvider, $locationProvider,
                        localStorageServiceProvider) {
                    localStorageServiceProvider.setStorageType('localStorage');
                    $locationProvider.html5Mode(true);

Dann muss noch eine Base gesetzt werden, das machen wir in unserer index.html.

<head>
      <base href="/">
</head>

Okay, put your RewriteEngines on

Den Request so umleiten, dass eine fertige HTML Seite zur Verfügung gestellt wird. Im Folgenden beschreibe ich das ganze. Wir haben uns entschieden, ein Java-Servlet für die Bereitstellung zu nutzen – man könnte auch eine PHP Page erszeugen lassen. Hauptsache am Ende wird eine HTML Seite rausgegeben.

Diese HMTL Page muss nicht „schön“ aussehen, sondern nur die relevanten Informtionen enthalten, die extrahiert werden können sollen.

  1. Wir definieren unser URL Pattern. Dieses soll wie folgt aussehen:
     eventkeeper.de/event?id=695

    Eine schöne kurze URL, die man verteilen kann.

  2. Zusätzlich legen wir ein URL Pattern fest, unter dem sich der statische Content befindet:
    eventkeeper.de/static/event?id=695

    Die Url für die Browseransicht sollte bekannt sein – diese wird für die Erstellung der Regeln auch benötigt.

  3. Wir verwenden einen Apache Webserver. Unser Virtual Host wird um folgenden Eintrag ergänzt:
    <IfModule mod_rewrite.c>
        RewriteEngine On
        RewriteCond %{HTTP_USER_AGENT} !(facebookexternalhit|Twitterbot|Pinterest|Google.*snippet)
        RewriteCond %{QUERY_STRING} id(.*)$
        RewriteRule ^/?(.*) /#/flyer?eventId%1 [NE,L,R=301]
                
        RewriteCond %{HTTP_USER_AGENT} (facebookexternalhit|Twitterbot|Pinterest|Google.*snippet) [NC]
        RewriteCond %{REQUEST_URI} !^/static
        RewriteCond %{QUERY_STRING} id(.*)$
        RewriteRule ^/?(.*) /static/event?id%1 [L,R=301]
    </IfModule>

    Das sorgt dafür, dass die Anfragen die an unsere URL gehen korrekt umgeleitet werden. Es wird dabei immer zunächst der HTTP_USER_AGENT Header ausgewertet. Die jeweiligen Bedingungen danach sorgen für die korrekte Umsetzung der Parameter, und unterbinden endlose Redirects (Prüfung auf „static“).

  4. Jetzt müssen wir auch den statischen Content unter eventkeeper.de/static/event?id=695 bereitstellen, den wir unter der neuen URL versprechen.
    Das machen wir mit Hilfe eines Java Servlets. Hier wird das Event via RestService geladen, und mit dem JSON dann ein HTML Template befüllt.

            ....
            HttpResponse httpResponse = httpclient.execute(target, getRequest);
            HttpEntity entity = httpResponse.getEntity();
            String jsonString = EntityUtils.toString(entity);
            logger.debug(jsonString);
            org.codehaus.jettison.json.JSONArray jsonArray = new org.codehaus.jettison.json.JSONArray(jsonString);
            org.codehaus.jettison.json.JSONObject jsonObject = (org.codehaus.jettison.json.JSONObject)jsonArray.get(0);
            String staticPage = templateManager.getStaticEventPage(jsonObject);
            
            BufferedInputStream input = new BufferedInputStream(new ByteArrayInputStream(
                    staticPage.getBytes()));
            BufferedOutputStream output = new BufferedOutputStream(
                    response.getOutputStream());
            byte[] buffer = new byte[8192];
            int length;
            while ((length = input.read(buffer)) > 0) {
                output.write(buffer, 0, length);
            }
            output.flush();

Das wars auch schon.

Die Vorschau in Facebook sieht nun viel besser aus:

angular_now_working_on_fb