Folge mir auf Twitter.

Webentwicklung - Webarchitekturen

Hochschule für Technik und Wirtschaft Berlin

Dipl.-Inform. Thomas Ziemer

Webentwicklung - Webarchitekturen

Dipl.-Inform. Thomas Ziemer

Webarchitektur (Frontend und Backend)

Webentwicklung - Webarchitekturen

Frontend (Dieser Foliensatz)

Webentwicklung - Webarchitekturen

JSON

JSON

Die JSON-Syntax wurde von der JavaScript Object Notation abgeleitet, also derjenigen Notation, mittels der man auf JavaScript-Objekte zugreift:

JavaScript Object Notation

var person = {
  "name": "John", // Strings erfordern doppelte Anführungszeichen!
  "age": 30,
  "rich": true,
  "cars": { // ein Objekt
    "car1": "BMW",
    "car2": "Audi"
  }
}
var person = {
  "name": "John",
  "age": 30,
  "rich": true, 
  "cars": ["BMW", "Audi"] // ein Array
}

JSON-Typen

Um in ein JSON-Objekt umgewandelt werden zu können, müssen die Werte eines JavaScript-Objekts einen der folgenden Typen besitzen:

Webentwicklung - Webarchitekturen

JSON-Elementzugriffe

JSON-Elementzugriff (lesend)

var person = {
  "name": "John",
  "age": 30,
  "rich": true,
  "address": {
    "street": "Oxford Street",
    "city": "London"
  },
  "cars": ["BMW", "Audi"]
}

var name = person.name; oder var name = person["name"];
var street = person.address.street;

JSON-Elementzugriff (schreibend)

var person = {
  "name": "John",
  "age": 30,
  "rich": true,
  "address": {
    "street": "Oxford Street",
    "city": "London"
  },
  "cars": ["BMW", "Audi"]
}

person.name = "Jane"; oder person["name"] = "Jane";
delete person.name; // der delete-Operator löscht Objekt-Eigenschaften

JSON-Elementzugriffe (Array)

var person = {
  "name": "John",
  "age": 30,
  "rich": true,
  "address": {
    "street": "Oxford Street",
    "city": "London"
  },
  "cars": ["BMW", "Audi"]
}

var car = person.cars[0];
person.cars[1] = "Mercedes";

JSON-Elementzugriffe (Array iterierend)

var person = {
  "name": "John",
  "rich": true,
  "address": {
    "street": "Oxford Street",
    "city": "London"
  },
  "cars": ["BMW", "Audi"]
}
// Autos iterieren und in HTML-Element schreiben
var carsListRef = document.getElementById("cars");
for (i in person.cars) {
  carsListRef.innerHTML += person.cars[i] + " ";
}

JSON-Typumwandlung (sozusagen type casting)

Es wird in JavaScript mittels Methoden der JSON-Klasse zwischen JavaScript- und JSON-Objekten hin und her konvertiert:

var jsObject = JSON.parse(jsonObject);
var jsonObject = JSON.stringify(jsObject);

Die stringify()-Methode kann auch mit JavaScript-Arrays umgehen:

var jsArray = ["John", "Peter", "Sally", "Jane"];
var jsonArray = JSON.stringify(jsArray);

Webentwicklung - Webarchitekturen

Datum als JSON-Eigenschaft

Datum als JSON-Eigenschaft (JSON → JS)

Der Datumstyp wird in einem JSON-Objekt nicht unterstützt.
Datumswerte müssen deshalb als String repräsentiert werden:

var jsonObject = '{"name": "Jane", "birth": "1969-01-04"}';
var jsObject = JSON.parse(jsonObject);
jsObject.birth = new Date(jsObject.birth);

Hier erkennt man deutlich, dass JavaScript alles andere ist, aber keine typsichere Sprache!

Datum als JSON-Eigenschaft (JS → JSON)

Die Methode JSON.stringify() konvertiert Datumswerte in einem JavaScript-Objekt automatisch in JSON-Strings:

var jsObject = {"name": "Jane", "today": new Date()};
var jsonObject = JSON.stringify(jsObject );

JavaScript-Funktionen sind in JSON-Objekten übrigens ebenfalls nicht erlaubt. Die stringify()-Methode ignoriert diese bei der Konvertierung eines JavaScript-Objekts.

reviver-Parameter in JSON

Der reviver-Parameter der parse()-Methode ist eine Funktion, die jede JSON-Eigenschaft prüft, und bei Bedarf eine Konvertierung des danach zurückgelieferten Wertes vornehmen kann:

var jsonObject = '{"name": "Jane", "birth": "1969-01-04"}';

var jsObject = JSON.parse(jsonObject, function(key, value) {
  if (key == "birth") {
    return new Date(value);
  } else {
    return value;
  }
});

Webentwicklung - Webarchitekturen

REST-Zugriff mittels JavaScript

Webarchitektur (Frontend-Backend-Schnittstelle)

Sowohl beim REST-Zugriff als auch beim Verschicken von Daten durch einen WebSocket wird auf der empfangenden Seite eine Callback-Methode aufgerufen.

REST-Zugriff mittels JavaScript


var xmlHttpRequest = new XMLHttpRequest();
var url = "https://host/rest/api/v1/aRestMethod/" + aParam;

// XMLHttpRequest.open(method, url[, async][, user][, password])
xmlHttpRequest.open("POST", url);
xmlHttpRequest.setRequestHeader("Content-type", "application/json");
xmlHttpRequest.onreadystatechange = function() {
  if (this.readyState === 4 && this.status === 200) {
    var jsResponseObject = JSON.parse(this.responseText);
    …
  }
};

// XMLHttpRequest.send([body]);
xmlHttpRequest.send(JSON.stringify(jsRequestObject));

REST-Zugriff mittels JavaScript (readyState)

readyState  State  Bedeutung 
0 UNSENT  Client has been created. open() not called yet. 
1 OPENED  open() has been called. 
2 HEADERS_RECEIVED  send() has been called,
headers and status are available. 
3 LOADING  Downloading; responseText holds partial data. 
4 DONE  The operation is complete

Webentwicklung - Webarchitekturen

Events und Timers

REST-Zugriff auslösen (event-getriggert)

HTML-Code:

<html>
  <body>
    <a onclick="saveProject();">Projekt speichern</a>
  </body>
</html>

JavaScript-Code (der korrespondierende Event-Listener):

function saveProject() {
  var xmlHttpSaveProject = new XMLHttpRequest();
  …  
}

Andere JavaScript-Events nutzen

Es gibt viele JavaScript-Events (hier finden Sie mehr), mit deren Hilfe man eine Funktionalität auslösen kann:

REST-Zugriff auslösen (timer-/event-getriggert)

// Event feuert nach 5.000 Millisekunden
var autoSaveEvent = setTimeout(saveProject, 5000);

function saveProject() {
  var xmlHttpSaveProject = new XMLHttpRequest();
  …  
}

Mit der Methode setInterval(function, milliseconds) kann man einen regelmäßigen Timer erstellen.
Die Methoden clearTimeout(timeoutVariable) bzw.
clearInterval(timerVariable) beenden einen Event bzw. Timer.

Webentwicklung - Webarchitekturen

Document Object Model (DOM)

Document Object Model (DOM)

Ein Browser analysiert ein HTML-Dokument und erstellt daraus im Arbeitsspeicher das Document Object Model, also eine Repräsentation dieses Dokuments, auf die man beispielsweise mit JavaScript zugreifen kann.

https://wiki.selfhtml.org/wiki/DOM

HTML-Dokument

<html>
  <head>
    <title>Document Object Model</title>
  </head>
  <body>
    <h1>Beispiel</h1>
    <p>Das ist ein <a href="demo.html">einfaches</a> Beispiel.</p>
    <!-- Dies ist ein Kommentar. -->
  </body>
</html>

Document Object Model

└─ html
   ├─ head
   │ ├─ #text: ↵
   │ ├─ title
   │ │  └─ #text: DOM
   │ └─ #text: ↵
   ├─ #text: ↵
   └─ body
      ├─ #text: ↵
      ├─ h1
      │  └─ #text: Document Object Model
      ├─ #text: ↵
      ├─ p
      │  ├─ #text: Das ist ein
      │  ├─ a href="demo.html"
      │  │  └─ #text: einfaches
      │  └─ #text: Beispiel.
      ├─ #text: ↵
      ├─ #comment: Dies ist ein Kommentar.
      └─ #text:

Document Object Model

Unterschieden werden: Elementknoten (gelb), Attributknoten (blau), Textknoten (rot) und Kommentare (grün).

Quelle:
wiki.selfhtml.org/wiki/JavaScript/DOM

DOM-Manipulation

Das Document Object Model ist nicht statisch, sondern kann durch DOM-Manipulation ausgelesen, verändert und erweitert werden:

JavaScript Zugriff über... 
getElementById()  ... die dokumentweit eindeutige Element-Id 
getElementsByName()  ... alle Elemente mit diesem Namen (Collection) 
getElementsByTagName()  ... alle HTML-Elemente dieses Typs (Collection) 
querySelector()  ... das erste Element mit dem CSS-Selektor
querySelectorAll()  ... alle Elemente mit dem CSS-Selektor (Collection) 

DOM-Manipulation

Das document-Objekt in JavaScript hält darüber hinaus verschiedene Collections mit den Referenzen von HTML-Elementen bestimmter Typen:

DOM-Manipulation

Man kann mit createElement(tagName) ein neues HTML-Element erstellen, und dieses mittels element.insertBefore() und element.appendChild() in das DOM einhängen.

DOM-Manipulation

DOM-Element können ausgelesen und verändert werden:

Weitere Eigenschaften der Elementknoten findet man hier.

Webentwicklung - Webarchitekturen

Local Storage

Local Storage

Mittels Local Storage aus dem Web Storage API werden Schlüssel-/Wertpaare persistent (dauerhaft) im Browser abgelegt:

Session Storage vs. Local Storage

Das Objekt sessionStorage ähnelt localStorage und hat auch dieselben Methoden. Die Schlüssel-/Wertpaare stehen jedoch nur während des Browsens zur Verfügung und werden beim Schließen der Webseite (des Tabs) bzw. des Browsers gelöscht.

Webentwicklung - Webarchitekturen

WebSockets

WebSockets

Conceptually, WebSocket is really just a layer on top of TCP. Basically it is intended to be as close to just exposing raw TCP to script as possible given the constraints of the Web.

RFC 6455

WebSockets

WebSockets helfen, das klassische MVC-Konzept in Web-Applikationen zu realisieren. Zuvor musste mit asynchronem Polling (MVC Model 2) "geschummelt" werden. Nunmehr lässt sich realisieren:

WebSockets

var url = "ws://localhost:8080/swxercise/ws/api/v1/anEndpoint";
var webSocket = new WebSocket(url);
 
// Callback-Methoden für die WebSocket-Kommunikation
webSocket.onopen =    function(e) { onWebSocketOpen(e) };
webSocket.onclose =   function(e) { onWebSocketClose(e) };
webSocket.onmessage = function(e) { onWebSocketMessage(e) };
webSocket.onerror =   function(e) { onWebSocketError(e) };

function onWebSocketMessage(e) {
   var data = JSON.parse(e.data);
}
function sendMessage(message) {
   if (webSocket.readyState === 1)
      webSocket.send(message);
}

WebSockets (readyState)

readyState  State  Bedeutung 
0 CONNECTING  The connection is not yet open. 
1 OPEN  The connection is open and ready to communicate. 
2 CLOSING The connection is in the process of closing. 
3 CLOSED The connection is closed or couldn't be opened. 

WebSockets

Eine WebSocket-Verbindung wird durch die Methode
webSocket.close([code,] [reason]) geschlossen.

Mit code kann ein optionaler Statuscode angegeben werden. Standardmäßig wird 1000 (Normal Closure) übertragen.

Mittels optionalem reason kann der Grund angegeben werden, aus dem die WebSocket-Verbindung geschlossen wird (maximal 123 Bytes of UTF-8 Text).

Weitere Statuscodes sind hier dokumentiert.

WebSocket-Sicherheitsmodell

WebSocket-Handshaking

Die Anforderung zum Aufbau eines WebSockets geht stets vom Browser aus. Der Server bestätigt die Anforderung (oder auch nicht) und hält die bereits etablierte TCP-Verbindung der HTTP-Anfrage dauerhaft offen. Sie wird danach als TCP-Socket verwendet.

Puh, fertig!

Nächster Foliensatz...