Monatsarchiv für März 2011

 
 

Protocol Relative URLs

Ist eine Webseite per https-Protokoll SSL-verschlüsselt aufrufbar, so müssen alle externen Objekte auf dieser Webseite ebenfalls über HTTPS geladen werden. Ist das nicht der Fall, gibt es im Internet-Explorer eine hässliche Meldung, bei anderen Browsern verschwindet einfach das begehrte Schloss-Icon.

Da Objekte (also Bilder, Scripte, CSS-Dateien usw.) meistens mit relativer Pfadangabe geladen werden, ist das aber kein Problem. Anders sieht das bei Benutzung eines CDN oder externen JS-Dateien, z.B. über Google APIs, aus. Hier muss nämlich die komplette URI zum Script angegeben werden, inklusive dem Protokoll. Das ist ein Problem, wenn die Seite sowohl über HTTP als auch HTTPS erreichbar ist. Abhilfe schafft das “network-path reference” Schema:

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
In diesem Fall würde jQuery wahlweise per http oder https geladen werden – je nach Kontext.

Google-Analytics

Der Google-Analytics Code zum Einbauen in die eigene Webseite sieht so oder so ähnlich aus:

<script type="text/javascript">
   var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
   document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>

Hier wird je nach Protokoll per document.write ein script-Tag erzeugt. Echt unschön. Mit einer protocol relative URL sähe das so aus:

<script type="text/javascript" src="//google-analytics.com/ga.js"></script>

Viel schöner! Warum benutzt dann Google aber keine protokoll-relativen URLs? Schuld ist mal wieder, wie so oft, der IE. Und zwar in der Version 6 – hier soll es je nach Sicherheitseinstellungen zu Zertifikats-Fehlermeldungen kommen. Wen weder den IE6 noch seine Sicherheitseinstellungen interessieren, kann sein GA-Script also protokoll-relativ einbinden. Ach ja, wo wir schon beim Internet Explorer sind: In der Version 7 und 8 läd dieser protokoll-relative <link> und @import Ressourcen leider zwei mal herunter.

Hosteurope vServer Ausfall! MTTR: 32 Stunden..

Ein Festplattencrash im Wirtssystem eines vServers Linux XL 4.0 von Hosteurope führte zu einer Downtime von Sage und Schreibe 32 Stunden. Beim Zurückspielen der von Hosteurope angelegten Backups gab es offensichtlich Schwierigkeiten. Während den Restore-Versuchen seitens Hosteurope war es nicht möglich, einfach einen frischen vServer unter der selben IP zu erhalten – ich habe mich, nachdem der Server bereits über 24 Stunden DOWN war, ja schon längst damit abgefunden, das Ding neu aufzusetzten und eigene Backups einzuspielen. Es blieb also nur: ausharren! Der Telefonsupport hat mir immer schön freundlich und verständnisvoll die Statusmeldungen vorgelesen – wirklich Helfen kann da einem aber offensichtlich keiner.

Backups macht man übrigens NUR um die Daten auch tatsächlich wiederherzustellen. Bei Hosteurope könnte man meinen, dass die Wiederherstellung eines vServers das ein oder andere Mal probiert wurde. Offenbar nicht so wirklich.

Disaster Recovery bei Hosteurope vServer: Ein Desaster!

Das SLA von Hosteurope liest sich ja ganz gut, ist aber im Ernstfall Schall und Rauch. Dort wird eine MTTR (mean time to repair, durchschnittliche Reparaturdauer) für einen Hardwaredefekt mit 4 (typisch: 2) Stunden angegeben! Bei Überschreitung der zugesicherten MTTR gibt es pro 30min. 1/30 der Monatsmiete zurück – maximal aber 50%. Für 32 Stunden Downtime gibt es jetzt also ganze 8,50€ Entschädigung – sofern man diese per Fax oder Brief beantragt.

Eine DNS-Umstellung zu Beginn der Downtime wäre im Nachhinein natürlich die beste Entscheidung gewesen. Die Aussagen vom Support sowie die Statusmeldungen (was als Synonym zu verstehen ist) haben aber stets ein baldiges Ende der Restore-Arbeiten versprochen.

Das hier einiges außerplanmäßig schief gelaufen sein muss, ist klar. Dennoch Frage ich mich, was dann den Mehrpreis von Hosteurope gerechtfertigt. vServer mit dieser Spezifikation bekommt man woanders für weniger als die Hälfte. Ebenfalls mit Labeln wie 100% Qualitätshardware” und “Professionelles Knowhow.

Bis gestern dachte ich, dass man bei Hosteurope tatsächlich mehr bekommt. In diesem Fall leider nicht. Dennoch sind die Probleme mit Hosteurope in der Gesamtheit wohl sehr gering. Zumindest war das immer mein Eindruck bei Recherchen im Internet. Als direkt Betroffener hilft das einem aber auch nicht weiter. Aber warten wir mal ab, ob sich Hosteurope dazu abschließend noch äußert.

Das ist die Chronologie der Statusmeldungen. Interessant: Die Störungsmeldung des parallel bereitgestellten vServers (leider mit anderer IP und somit unbrauchbar) und eine 6 Stunden Downtime während Wartungsarbeiten nur 4 Wochen zuvor. Laut Pingdom macht das seit Beginn der Messungen (01.02.2011) eine Uptime von nur 96,81%.

Hash-Bangs (#!) in URLs

Hash-Bangs  in URLs sind stark in Mode gekommen. Facebook, Twitter, DeviantART und viele weitere ganz oder teilweise auf Javascript/Ajax basierende Seiten benutzen es.

Alles was nach einer Raute in der URL kommt, ist der sog. named anchor. Ursprünglich dazu gedacht um zu einem <a>nchor mit diesem Namen, oder Element mit dieser ID zu scrollen/springen. Das ist praktisch, wenn man auf eine gewisse Stelle einer langen HTML-Seite verlinken will. Bei der Wikipedia ist z.B. das Inhaltsverzeichnis immer auch ein Anker-Link zur jeweiligen Sektion. Außerdem erzeugt der Sprung sinnigerweise einen History-Back-Eintrag.

Der Hash-Bang (oder Shebang) in der URL ist eine Google-Erfindung (oder besser: Notlösung) um Ajax-Content zu Crawlen. Diese Notlösung scheint sich aber seit der Definition durch Google erstaunlich schnell auszubreiten. Die Tatsache, dass andere Suchmaschinen/Crawler/Caches/Bots diese URLs nicht unterscheiden, da sie den anchor-part grundsätzlich ignorieren, scheint der Sache keinen Abbruch zu tun. Zudem gibt es bei dieser-URL-Struktur keine graceful degradation, da der anchor-part Serverseitig gar nicht ankommt. Wenn das Javascript also fehlerfaft ist, gibt es gar nichts mehr zu sehen. Das hat Gawker zuletzt schmerzlich erfahren müssen.

Was ist dann aber der Vorteil einer solchen URL-Struktur:

http://lifehacker.com/#!5622470/eight-clever-ways-to-take-advantage-of-free-c..
anstelle von:
http://lifehacker.com/5622470/eight-clever-ways-to-take-advantage-of-free-c..
Ich sehe keinen! Bis auf die Tatsache, dass beim Laden der zweiten Seite etwas weniger Traffic ensteht – was aber in keinem Verhältnis zu den Nachteilen steht.

Wie funktioniert’s eigentlich?

Serverseitig kommt der Anchor nicht an. Mit Javascript ist er Clientseitig aber sehr wohl auslesbar (via document.location.hash). Mit einem setInterval muss  der hash permanent auf Änderungen überprüft werden – echt häßlich! Im Falle einer Änderung wird der Hash geparst und ein XMLHTTP-Request gesendet. Das Result dieses Requests ersetzt dann Teile des Contents.

Das hat den nervigen Effekt, dass z.B. beim Aufruf dieser URL

http://browse.deviantart.com/#/d1muyik

zunächst die DevianArt-Startseite geladen wird und erst dann das JS eingreift und das gewünschte Bild anzeigt. NO-GO.

Die Rettung: HTML5 History API?

Die History-API gab es schon in früheren HTML-Versionen – allerdings nur lesend z.B. via history.back(). Ab HTML5 ist auch ein schreibender Zugriff auf die History möglich. Man kann also per Javascript neue History-Einträge erzeugen und so den Inhalt der Adressbar ändern, ohne eine neue Seite aufzurufen. Yay! Betätigt der Benutzer anschließend den Zurück-Button wir ein ensprechendes Event gefeuert. Das würde das Erzeugen von History-Einträgen via Anker-Sprünge und damit die Hash-Bangs in URLs ein für alle mal abschaffen. Content könnte teilweise per AJAX-Request nachgeladen werden und die neu entstehende Seite hätte trotzdem Ihre eindeutige URL und wäre auch direkt über diese aufzurufen.

Lediglich Firefox ab Version 4 und Safari ab Version 5 unterstützen schreibende Zugriffe auf die History-API im Moment. Kein IE9 und kein Opera 11. Prinzipiell kann aber bei Browsern, die die History-API nicht unterstzützen auf herkömmliche URLs ohne das Nachladen via AJAX zurückgefallen werden.

xtc: Land-Dropdown im Warenkorb

Die Versandkosten im Warenkorb anzuzeigen ist ein toller Service. So sieht man direkt im Warenkorb den exakten Gesamtbetrag und die Gäste müssen sich nicht extra registrieren um die richtigen Versandkosten angezeigt zu bekommen. Bei international ausgerichteten Online-Shops macht es außerdem Sinn, den Gast über ein Land-Dropdown das Zielland festlegen zu lassen. So werden die Versandkosten entsprechend berechnet und auch die Preise inkl. oder exkl. MwSt. angezeigt.

Kommt für das ausgewählte Land nur eine Versandmethode in Frage, so wird gleich der Gesamtbetrag angezeigt. Kommen mehrere Versandarten in Frage, werden diese samt kosten aufgelistet.

Im xtcModified-Forum bin ich auch einen Thread gestoßen in dem beschrieben wird, wie man Versandkosten im Warenkorb anzeigt. Diese Änderung habe ich um das Land-Dropdown erweitert. Die Mehrwehrtssteuer werden dem ausgewähltem Land entsprechend berechnet. Das gewählte Land wird auch in das create_account-Formular übernommen.

Alle geänderten Files gibt es hier als Download oder hier als Patch – jeweils gegen die aktuelle xtcModified v1.05. Prinzipiell sollte das auch mit XTC SP2.1 funktionieren.

Im Detail:

/create_account.php und /create_account_guest.php
Suche:
if (isset($_POST['country'])) {
  $selected = $_POST['country'];
} else {
  $selected = STORE_COUNTRY;
}
 
Ersetze durch:
if (isset($_POST['country'])) {
  $selected = $_POST['country'];
} else if (isset($_SESSION['country'])) {
  $selected = $_SESSION['country'];
} else {
 $selected = STORE_COUNTRY;
}
 
/includes/cart_actions.php
Suche:
case 'update_product' :
 
Ersetze durch:
case 'update_product' :
 // Versandkosten im Warenkorb
 if (isset($_POST['country'])) {
 $_SESSION['country'] = xtc_remove_non_numeric($_POST['country']);
 }
 //-
 
/includes/classes/xtcPrice.php
Suche:
$this->TAX[$zones_data['class']]=xtc_get_tax_rate($zones_data['class']);
 
Ersetze durch:
// Versandkosten im Warenkorb
$country_id = -1;
if (isset($_SESSION['country']) && !isset($_SESSION['customer_id'])) {
  $country_id = $_SESSION['country'];
}
$this->TAX[$zones_data['class']]=xtc_get_tax_rate($zones_data['class'], $country_id);
//-
 
/includes/modules/order_details_cart.php
Suche:
$module_smarty->assign('TOTAL_CONTENT', $total_content);
 
Ersetze durch:
// Versandkosten im Warenkorb
include DIR_FS_CATALOG.'/includes/shipping_estimate.php';
//-
$module_smarty->assign('TOTAL_CONTENT', $total_content);
 
/templates/xtc5/modules/order_details.html
Suche:
<tr>
 <td colspan="4">{$UST_CONTENT}<strong>{$TOTAL_CONTENT}</strong>{if $SHIPPING_INFO}{$SHIPPING_INFO}{/if}</td>
 <td>&nbsp;</td>
 </tr>
 
Ersetze durch:
<tr>
 <td colspan="5">
 {if $SELECT_COUNTRY}{#text_country#} {$SELECT_COUNTRY}{/if}<br />
 </td>
 </tr>
 <tr>
 <td colspan="2">
 &nbsp;
 </td>
 <td colspan="3">
 {if $UST_CONTENT}{$UST_CONTENT}{else}<strong>{php}printf(TAX_INFO_EXCL, ''){/php}</strong><br />{/if}
 <u>{$TOTAL_CONTENT}</u><br />
 {foreach name=aussen item=shipping_data from=$shipping_content}
 {$shipping_data.NAME} ({$COUNTRY}): {$shipping_data.VALUE}<br />
 {/foreach}
 {if $total}
 <strong>{#text_total#}: {$total}</strong>
 {/if}
 </td>
 </tr>

Außerdem die Datei “shipping_esitmate.php” im Ordner /includes platzieren.