reverse-proxy-middleware 0.0.145 → 0.0.147
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/helper.d.ts +3 -2
- package/dist/helper.js +78 -20
- package/dist/index.js +94 -31
- package/dist/type.d.ts +5 -2
- package/package.json +27 -20
- package/readme.md +519 -329
package/readme.md
CHANGED
|
@@ -7,11 +7,13 @@ License
|
|
|
7
7
|
-------
|
|
8
8
|
|
|
9
9
|
This library written by Torben Sickert stands under a creative commons naming
|
|
10
|
-
|
|
10
|
+
4.0 international license.
|
|
11
|
+
See https://creativecommons.org/licenses/by/4.0/deed.de
|
|
11
12
|
endregion -->
|
|
12
13
|
|
|
13
14
|
<!--|deDE:Projektstatus-->
|
|
14
|
-
|
|
15
|
+
<!--|frFR:Statut du projet-->
|
|
16
|
+
Project status
|
|
15
17
|
--------------
|
|
16
18
|
|
|
17
19
|
[](https://www.npmjs.com/package/reverse-proxy-middleware)
|
|
@@ -31,16 +33,38 @@ Project Status
|
|
|
31
33
|
[](https://github.com/thaibault/reverse-proxy-middleware/actions/workflows/deploy-web-documentation.yaml)
|
|
32
34
|
[](https://tsickert.com/reverse-proxy-middleware)
|
|
33
35
|
|
|
34
|
-
<!--|deDE:
|
|
36
|
+
<!--|deDE:Einsatzmöglichkeiten-->
|
|
37
|
+
<!--|frFR:Cas d'utilisation-->
|
|
35
38
|
Use case
|
|
36
39
|
--------
|
|
37
40
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
A small reverse proxy configured with a single JSON file. Each incoming request
|
|
42
|
+
is passed on to one of the configured backends ("forwarders"). Before that, the
|
|
43
|
+
proxy can ask third party services ("state APIs"), e.g. a bot filter like
|
|
44
|
+
reCAPTCHA or friendlycaptcha or an authentication service, and answer the
|
|
45
|
+
request itself depending on their responses. Request and response headers can
|
|
46
|
+
be rewritten on the way through. All decisions are short JavaScript
|
|
47
|
+
expressions inside the configuration.
|
|
48
|
+
<!--deDE:
|
|
49
|
+
Ein kleiner Reverse-Proxy, der über eine einzige JSON-Datei konfiguriert
|
|
50
|
+
wird. Jede eingehende Anfrage wird an eines der konfigurierten Backends
|
|
51
|
+
("Forwarder") weitergereicht. Vorher kann der Proxy Dienste von
|
|
52
|
+
Drittanbietern ("State-APIs") befragen, z. B. einen Bot-Filter wie
|
|
53
|
+
reCAPTCHA oder friendlycaptcha oder einen Authentifizierungsdienst, und
|
|
54
|
+
die Anfrage abhängig von deren Antworten selbst beantworten. Anfrage- und
|
|
55
|
+
Antwort-Header lassen sich unterwegs umschreiben. Alle Entscheidungen
|
|
56
|
+
sind kurze JavaScript-Ausdrücke in der Konfiguration.
|
|
57
|
+
-->
|
|
58
|
+
<!--frFR:
|
|
59
|
+
Un petit proxy inverse configuré par un seul fichier JSON. Chaque requête
|
|
60
|
+
entrante est transmise à l'un des backends configurés ("forwarders").
|
|
61
|
+
Auparavant, le proxy peut interroger des services tiers ("state APIs"),
|
|
62
|
+
par exemple un filtre anti-bots comme reCAPTCHA ou friendlycaptcha ou un
|
|
63
|
+
service d'authentification, et répondre lui-même à la requête selon
|
|
64
|
+
leurs réponses. Les en-têtes de requête et de réponse peuvent être
|
|
65
|
+
réécrits au passage. Toutes les décisions sont de courtes expressions
|
|
66
|
+
JavaScript dans la configuration.
|
|
67
|
+
-->
|
|
44
68
|
|
|
45
69
|
<div class="wd-table-of-contents">
|
|
46
70
|
<h2 id="content">Content<!--deDE:Inhalt--><!--frFR:Contenu--></h2>
|
|
@@ -50,416 +74,582 @@ forwarded requests.
|
|
|
50
74
|
Installation
|
|
51
75
|
------------
|
|
52
76
|
|
|
53
|
-
|
|
54
|
-
|
|
77
|
+
Install the command globally via npm and start it in the folder which holds
|
|
78
|
+
your "configuration.json":
|
|
55
79
|
<!--deDE:
|
|
56
|
-
Sie
|
|
57
|
-
|
|
58
|
-
oder über ein CDN abrufen:
|
|
80
|
+
Installieren Sie den Befehl global über npm und starten Sie ihn in dem
|
|
81
|
+
Ordner, der Ihre "configuration.json" enthält:
|
|
59
82
|
-->
|
|
60
83
|
<!--frFR:
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
puis l'intégrer dans une page HTML ou la récupérer via un CDN:
|
|
84
|
+
Installez la commande globalement via npm et lancez-la dans le dossier
|
|
85
|
+
qui contient votre "configuration.json":
|
|
64
86
|
-->
|
|
65
87
|
|
|
66
88
|
```bash
|
|
67
|
-
npm install reverse-proxy-middleware
|
|
89
|
+
npm install --global reverse-proxy-middleware
|
|
90
|
+
reverse-proxy-middleware
|
|
68
91
|
```
|
|
69
92
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
Simple reverse proxy request from `http://localhost:8080` to
|
|
78
|
-
`https://www.google.com` without modifying the entire request.
|
|
93
|
+
Or run the container image and mount the configuration into it:
|
|
94
|
+
<!--deDE:
|
|
95
|
+
Oder starten Sie das Container-Image und binden Sie die Konfiguration
|
|
96
|
+
ein:
|
|
97
|
+
-->
|
|
98
|
+
<!--frFR:Ou lancez l'image de conteneur et montez-y la configuration:-->
|
|
79
99
|
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
100
|
+
```bash
|
|
101
|
+
docker run \
|
|
102
|
+
--name reverse-proxy-middleware \
|
|
103
|
+
--publish 8080:8080 \
|
|
104
|
+
--rm \
|
|
105
|
+
--volume "$(pwd)/configuration.json:/application/configuration.json" \
|
|
106
|
+
ghcr.io/thaibault/reverse-proxy-middleware:latest
|
|
88
107
|
```
|
|
89
108
|
|
|
90
|
-
|
|
91
|
-
|
|
109
|
+
"systemd.service" in this repository is a unit which runs the container in
|
|
110
|
+
the Docker network "proxy" (e.g. behind the
|
|
111
|
+
[proxy](https://tsickert.com/proxy) project) and reads its configuration from
|
|
112
|
+
"/srv/http/reverse-proxy-middleware/configuration.json".
|
|
113
|
+
<!--deDE:
|
|
114
|
+
"systemd.service" in diesem Repository ist eine Unit, die den Container
|
|
115
|
+
im Docker-Netzwerk "proxy" betreibt (z. B. hinter dem Projekt
|
|
116
|
+
[proxy](https://tsickert.com/proxy)) und ihre Konfiguration aus
|
|
117
|
+
"/srv/http/reverse-proxy-middleware/configuration.json" liest.
|
|
118
|
+
-->
|
|
119
|
+
<!--frFR:
|
|
120
|
+
"systemd.service" dans ce dépôt est une unité qui exécute le conteneur
|
|
121
|
+
dans le réseau Docker "proxy" (par exemple derrière le projet
|
|
122
|
+
[proxy](https://tsickert.com/proxy)) et lit sa configuration depuis
|
|
123
|
+
"/srv/http/reverse-proxy-middleware/configuration.json".
|
|
124
|
+
-->
|
|
92
125
|
|
|
93
|
-
|
|
126
|
+
Configuration
|
|
127
|
+
-------------
|
|
94
128
|
|
|
95
|
-
|
|
96
|
-
|
|
129
|
+
On start, the defaults under the key "configuration" in
|
|
130
|
+
[package.json](package.json) are extended by "configuration.json" and then by
|
|
131
|
+
"secure-configuration.json" from the current working directory. Both files
|
|
132
|
+
are optional, the second one is meant for secrets. The top level options are:
|
|
133
|
+
<!--deDE:
|
|
134
|
+
Beim Start werden die Standardwerte unter dem Schlüssel "configuration"
|
|
135
|
+
in [package.json](package.json) durch "configuration.json" und danach
|
|
136
|
+
durch "secure-configuration.json" aus dem aktuellen Arbeitsverzeichnis
|
|
137
|
+
erweitert. Beide Dateien sind optional, die zweite ist für Geheimnisse
|
|
138
|
+
gedacht. Die Optionen der obersten Ebene sind:
|
|
139
|
+
-->
|
|
140
|
+
<!--frFR:
|
|
141
|
+
Au démarrage, les valeurs par défaut sous la clé "configuration" dans
|
|
142
|
+
[package.json](package.json) sont étendues par "configuration.json" puis
|
|
143
|
+
par "secure-configuration.json" du répertoire de travail courant. Les
|
|
144
|
+
deux fichiers sont facultatifs, le second est destiné aux secrets. Les
|
|
145
|
+
options de premier niveau sont:
|
|
146
|
+
-->
|
|
97
147
|
|
|
98
|
-
|
|
148
|
+
- "port" (default: the environment variable "PORT" or "8080"): where the proxy listens.<!--deDE:"port" (Standard: die Umgebungsvariable "PORT" oder "8080"): wo der Proxy lauscht.--><!--frFR:"port" (par défaut: la variable d'environnement "PORT" ou "8080"): où le proxy écoute.-->
|
|
149
|
+
- "host" (default empty, meaning all network interfaces): the address to listen on, e.g. "127.0.0.1".<!--deDE:"host" (Standard leer, also alle Netzwerkschnittstellen): die Adresse, auf der gelauscht wird, z. B. "127.0.0.1".--><!--frFR:"host" (vide par défaut, donc toutes les interfaces réseau): l'adresse d'écoute, par exemple "127.0.0.1".-->
|
|
150
|
+
- "forwarders": the backends, see below.<!--deDE:"forwarders": die Backends, siehe unten.--><!--frFR:"forwarders": les backends, voir ci-dessous.-->
|
|
151
|
+
- "parseBody" (default "false"): parses JSON request bodies for expressions.<!--deDE:"parseBody" (Standard "false"): wertet JSON-Anfragekörper für Ausdrücke aus.--><!--frFR:"parseBody" (par défaut "false"): analyse les corps de requête JSON pour les expressions.-->
|
|
152
|
+
- "logLevel" (default "info"): one of "debug", "info", "warn", "error" and "critical". "debug" logs every forwarded header.<!--deDE:"logLevel" (Standard "info"): einer von "debug", "info", "warn", "error" und "critical". "debug" protokolliert jeden weitergeleiteten Header.--><!--frFR:"logLevel" (par défaut "info"): l'un de "debug", "info", "warn", "error" et "critical". "debug" journalise chaque en-tête transmis.-->
|
|
153
|
+
- "publicKeyPath" and "privateKeyPath": certificate and key files which switch the proxy to HTTPS, see below.<!--deDE:"publicKeyPath" und "privateKeyPath": Zertifikats- und Schlüsseldatei, die den Proxy auf HTTPS umstellen, siehe unten.--><!--frFR:"publicKeyPath" et "privateKeyPath": fichiers de certificat et de clé qui font passer le proxy en HTTPS, voir ci-dessous.-->
|
|
154
|
+
- "nodeServerOptions": further options of the HTTPS server, see [Node.js](https://nodejs.org/api/https.html#httpscreateserveroptions-requestlistener).<!--deDE:"nodeServerOptions": weitere Optionen des HTTPS-Servers, siehe [Node.js](https://nodejs.org/api/https.html#httpscreateserveroptions-requestlistener).--><!--frFR:"nodeServerOptions": autres options du serveur HTTPS, voir [Node.js](https://nodejs.org/api/https.html#httpscreateserveroptions-requestlistener).-->
|
|
99
155
|
|
|
100
|
-
|
|
156
|
+
### HTTPS
|
|
101
157
|
|
|
102
|
-
|
|
158
|
+
With "publicKeyPath" and "privateKeyPath" set, the proxy only accepts HTTPS
|
|
159
|
+
connections. Relative paths start at the working directory, the files are
|
|
160
|
+
read on start:
|
|
161
|
+
<!--deDE:
|
|
162
|
+
Sind "publicKeyPath" und "privateKeyPath" gesetzt, akzeptiert der Proxy
|
|
163
|
+
nur HTTPS-Verbindungen. Relative Pfade beginnen im Arbeitsverzeichnis,
|
|
164
|
+
die Dateien werden beim Start gelesen:
|
|
165
|
+
-->
|
|
166
|
+
<!--frFR:
|
|
167
|
+
Lorsque "publicKeyPath" et "privateKeyPath" sont définis, le proxy
|
|
168
|
+
n'accepte que des connexions HTTPS. Les chemins relatifs partent du
|
|
169
|
+
répertoire de travail, les fichiers sont lus au démarrage:
|
|
170
|
+
-->
|
|
171
|
+
|
|
172
|
+
```JSON
|
|
103
173
|
{
|
|
104
|
-
|
|
105
|
-
"
|
|
106
|
-
"host": "www.bing.com",
|
|
107
|
-
"useExpression": "Math.random() < 0.5"
|
|
108
|
-
},
|
|
109
|
-
|
|
110
|
-
"google": {
|
|
111
|
-
"host": "www.google.com"
|
|
112
|
-
}
|
|
113
|
-
}
|
|
174
|
+
"publicKeyPath": "certificate.pem",
|
|
175
|
+
"privateKeyPath": "key.pem"
|
|
114
176
|
}
|
|
115
177
|
```
|
|
116
178
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
179
|
+
Encrypted connections always use HTTP/1.1. Certificate and key end up in
|
|
180
|
+
"nodeServerOptions" as "cert" and "key" unless these are given there already.
|
|
181
|
+
<!--deDE:
|
|
182
|
+
Verschlüsselte Verbindungen nutzen immer HTTP/1.1. Zertifikat und
|
|
183
|
+
Schlüssel landen als "cert" und "key" in "nodeServerOptions", sofern
|
|
184
|
+
diese dort nicht schon angegeben sind.
|
|
185
|
+
-->
|
|
186
|
+
<!--frFR:
|
|
187
|
+
Les connexions chiffrées utilisent toujours HTTP/1.1. Le certificat et
|
|
188
|
+
la clé sont placés dans "nodeServerOptions" sous "cert" et "key", sauf
|
|
189
|
+
s'ils y sont déjà indiqués.
|
|
190
|
+
-->
|
|
123
191
|
|
|
124
|
-
|
|
192
|
+
<!--|deDE:Weiterleitung-->
|
|
193
|
+
<!--|frFR:Redirection-->
|
|
194
|
+
### Simple forwarding
|
|
125
195
|
|
|
126
|
-
|
|
127
|
-
|
|
196
|
+
This configuration passes every request on "http://localhost:8080" to
|
|
197
|
+
"https://example.com" unchanged:
|
|
198
|
+
<!--deDE:
|
|
199
|
+
Diese Konfiguration reicht jede Anfrage an "http://localhost:8080"
|
|
200
|
+
unverändert an "https://example.com" weiter:
|
|
201
|
+
-->
|
|
202
|
+
<!--frFR:
|
|
203
|
+
Cette configuration transmet telle quelle chaque requête sur
|
|
204
|
+
"http://localhost:8080" à "https://example.com":
|
|
205
|
+
-->
|
|
128
206
|
|
|
129
|
-
```
|
|
207
|
+
```JSON
|
|
130
208
|
{
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
"headerTransformations": {
|
|
136
|
-
"send": {
|
|
137
|
-
"source": "/X-Special-Client-Header-Name: (.+)/gi",
|
|
138
|
-
"target": "'New-Header-Name: $1'"
|
|
139
|
-
},
|
|
140
|
-
|
|
141
|
-
"retrieve": {
|
|
142
|
-
"source": "/set-cookie: (.+)/gi",
|
|
143
|
-
"target": "'X-Prevented-Cookie: $1'"
|
|
209
|
+
"forwarders": {
|
|
210
|
+
"example": {
|
|
211
|
+
"host": "example.com"
|
|
144
212
|
}
|
|
145
|
-
}
|
|
146
213
|
}
|
|
147
|
-
}
|
|
148
214
|
}
|
|
149
215
|
```
|
|
150
216
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
```
|
|
154
|
-
curl \
|
|
155
|
-
--header 'X-Special-Client-Header-Name: value' \
|
|
156
|
-
--verbose \
|
|
157
|
-
http://localhost:8080 \
|
|
158
|
-
1>/dev/null
|
|
217
|
+
```bash
|
|
218
|
+
curl --verbose http://localhost:8080
|
|
159
219
|
```
|
|
160
220
|
|
|
161
|
-
|
|
162
|
-
"
|
|
163
|
-
|
|
164
|
-
|
|
221
|
+
A forwarder has the following options, the defaults come from the special
|
|
222
|
+
forwarder "base":
|
|
223
|
+
<!--deDE:
|
|
224
|
+
Ein Forwarder hat die folgenden Optionen, die Standardwerte stammen vom
|
|
225
|
+
besonderen Forwarder "base":
|
|
226
|
+
-->
|
|
227
|
+
<!--frFR:
|
|
228
|
+
Un forwarder possède les options suivantes, les valeurs par défaut
|
|
229
|
+
viennent du forwarder spécial "base":
|
|
230
|
+
-->
|
|
165
231
|
|
|
166
|
-
|
|
232
|
+
- "host" (default "localhost"), "port" (default "443") and "tls" (default "true"): the backend.<!--deDE:"host" (Standard "localhost"), "port" (Standard "443") und "tls" (Standard "true"): das Backend.--><!--frFR:"host" (par défaut "localhost"), "port" (par défaut "443") et "tls" (par défaut "true"): le backend.-->
|
|
233
|
+
- "rejectUnauthorized" (default "false"): set it to "true" to only accept backends with a valid certificate.<!--deDE:"rejectUnauthorized" (Standard "false"): auf "true" setzen, um nur Backends mit gültigem Zertifikat zu akzeptieren.--><!--frFR:"rejectUnauthorized" (par défaut "false"): le mettre à "true" pour n'accepter que les backends ayant un certificat valide.-->
|
|
234
|
+
- "useExpression" (default "true"): decides whether this forwarder takes the request.<!--deDE:"useExpression" (Standard "true"): entscheidet, ob dieser Forwarder die Anfrage übernimmt.--><!--frFR:"useExpression" (par défaut "true"): décide si ce forwarder prend la requête.-->
|
|
235
|
+
- "headerTransformations": rewrites headers, see below.<!--deDE:"headerTransformations": schreibt Header um, siehe unten.--><!--frFR:"headerTransformations": réécrit les en-têtes, voir ci-dessous.-->
|
|
236
|
+
- "stateAPIs": requests to third party services, see below.<!--deDE:"stateAPIs": Anfragen an Dienste von Drittanbietern, siehe unten.--><!--frFR:"stateAPIs": requêtes vers des services tiers, voir ci-dessous.-->
|
|
167
237
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
238
|
+
For a plain HTTP backend set "tls" to "false" and "port" to e.g. "80".
|
|
239
|
+
<!--deDE:
|
|
240
|
+
Für ein reines HTTP-Backend setzen Sie "tls" auf "false" und "port" z.
|
|
241
|
+
B. auf "80".
|
|
242
|
+
-->
|
|
243
|
+
<!--frFR:
|
|
244
|
+
Pour un backend HTTP simple, mettez "tls" à "false" et "port" par
|
|
245
|
+
exemple à "80".
|
|
246
|
+
-->
|
|
173
247
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
given request.
|
|
248
|
+
<!--|deDE:Anfragen auf mehrere Backends verteilen-->
|
|
249
|
+
<!--|frFR:Répartir les requêtes sur plusieurs backends-->
|
|
250
|
+
### Distributing requests
|
|
178
251
|
|
|
179
|
-
|
|
252
|
+
Forwarders are tried in alphabetical order of their names. The first one whose
|
|
253
|
+
"useExpression" results in "true" gets the request. This distributes requests
|
|
254
|
+
randomly between two backends, like a basic load balancer:
|
|
255
|
+
<!--deDE:
|
|
256
|
+
Forwarder werden in alphabetischer Reihenfolge ihrer Namen geprüft. Der
|
|
257
|
+
erste, dessen "useExpression" "true" ergibt, erhält die Anfrage. So
|
|
258
|
+
werden Anfragen zufällig auf zwei Backends verteilt, wie bei einem
|
|
259
|
+
einfachen Load-Balancer:
|
|
260
|
+
-->
|
|
261
|
+
<!--frFR:
|
|
262
|
+
Les forwarders sont essayés dans l'ordre alphabétique de leurs noms. Le
|
|
263
|
+
premier dont "useExpression" donne "true" reçoit la requête. Ainsi, les
|
|
264
|
+
requêtes sont réparties aléatoirement entre deux backends, comme avec un
|
|
265
|
+
simple répartiteur de charge:
|
|
266
|
+
-->
|
|
180
267
|
|
|
181
|
-
```
|
|
268
|
+
```JSON
|
|
182
269
|
{
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
"stateAPIs": {
|
|
188
|
-
"name": "sense",
|
|
189
|
-
"url": "https://www.google.com/search?q=${data.question}",
|
|
190
|
-
|
|
191
|
-
"data": {
|
|
192
|
-
"question": "What is the meaning of life?"
|
|
270
|
+
"forwarders": {
|
|
271
|
+
"first": {
|
|
272
|
+
"host": "first.example.com",
|
|
273
|
+
"useExpression": "Math.random() < 0.5"
|
|
193
274
|
},
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
"pre": "request.headers['ask-for-sense-of-live'] ? true : null",
|
|
197
|
-
"post": "response.statusCode >= 200 && response.statusCode < 300 ? null : response.statusCode"
|
|
275
|
+
"second": {
|
|
276
|
+
"host": "second.example.com"
|
|
198
277
|
}
|
|
199
|
-
}
|
|
200
278
|
}
|
|
201
|
-
}
|
|
202
279
|
}
|
|
203
280
|
```
|
|
204
281
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
"
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
--verbose \
|
|
219
|
-
http://localhost:8080 \
|
|
220
|
-
1>/dev/null
|
|
221
|
-
```
|
|
222
|
-
|
|
223
|
-
This should result in a simple response but:
|
|
224
|
-
|
|
225
|
-
```curl --verbose http://localhost:8080 1>/dev/null```
|
|
226
|
-
|
|
227
|
-
will finally request "www.bing.com".
|
|
228
|
-
|
|
229
|
-
Pre and post evaluations can have various results. The meanings of them are
|
|
230
|
-
described here:
|
|
231
|
-
|
|
232
|
-
### Pre-Evaluation Results
|
|
233
|
-
|
|
234
|
-
| Result | Meaning |
|
|
235
|
-
|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
236
|
-
| break (string) | Do not evaluate subsequent pre evaluations. |
|
|
237
|
-
| null or undefined | Just jump to the next evaluation to run. |
|
|
238
|
-
| true (boolean) | Use this state api configuration. Run the configured request. |
|
|
239
|
-
| false (boolean) | Do not use this state api and to not run subsequent pre evaluations. |
|
|
240
|
-
| code (number) | Answer client request with provided http status code and do not run any subsequent pre-evaluations, state-api request or request forwarding to the underlying backend. |
|
|
241
|
-
|
|
242
|
-
### Post-Evaluation Results
|
|
243
|
-
|
|
244
|
-
| Result | Meaning |
|
|
245
|
-
|-------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
246
|
-
| break (string) | Do not evaluate subsequent post evaluations. |
|
|
247
|
-
| null or undefined | Just jump to the next evaluation to run. |
|
|
248
|
-
| code (number) | Answer client request with provided http status code and do not run any subsequent post-evaluations, state-api request or request forwarding to the underlying backend. |
|
|
282
|
+
Expressions can also route by path, e.g.
|
|
283
|
+
"request.url.startsWith('/api/')". If no forwarder matches, the client gets
|
|
284
|
+
status code "502".
|
|
285
|
+
<!--deDE:
|
|
286
|
+
Ausdrücke können auch nach Pfad weiterleiten, z. B.
|
|
287
|
+
"request.url.startsWith('/api/')". Passt kein Forwarder, erhält der Client
|
|
288
|
+
den Statuscode "502".
|
|
289
|
+
-->
|
|
290
|
+
<!--frFR:
|
|
291
|
+
Les expressions peuvent aussi aiguiller selon le chemin, par exemple
|
|
292
|
+
"request.url.startsWith('/api/')". Si aucun forwarder ne correspond, le
|
|
293
|
+
client reçoit le code de statut "502".
|
|
294
|
+
-->
|
|
249
295
|
|
|
250
|
-
|
|
296
|
+
<!--|deDE:Header umschreiben-->
|
|
297
|
+
<!--|frFR:Réécrire les en-têtes-->
|
|
298
|
+
### Rewriting headers
|
|
251
299
|
|
|
252
|
-
|
|
253
|
-
|
|
300
|
+
"send" transformations apply to the request header sent to the backend,
|
|
301
|
+
"retrieve" transformations to the response header sent back to the client.
|
|
302
|
+
"source" is an expression resulting in a regular expression or string to
|
|
303
|
+
search for, "target" one resulting in its replacement:
|
|
304
|
+
<!--deDE:
|
|
305
|
+
"send"-Transformationen gelten für den Anfrage-Header, der an das Backend
|
|
306
|
+
geht, "retrieve"-Transformationen für den Antwort-Header, der zum Client
|
|
307
|
+
zurückgeht. "source" ist ein Ausdruck, der einen regulären Ausdruck oder
|
|
308
|
+
eine zu suchende Zeichenkette ergibt, "target" einer, der deren Ersatz
|
|
309
|
+
ergibt:
|
|
310
|
+
-->
|
|
311
|
+
<!--frFR:
|
|
312
|
+
Les transformations "send" s'appliquent à l'en-tête de requête envoyé au
|
|
313
|
+
backend, les transformations "retrieve" à l'en-tête de réponse renvoyé au
|
|
314
|
+
client. "source" est une expression donnant une expression régulière ou
|
|
315
|
+
une chaîne à rechercher, "target" une expression donnant son
|
|
316
|
+
remplacement:
|
|
317
|
+
-->
|
|
254
318
|
|
|
255
|
-
```
|
|
319
|
+
```JSON
|
|
256
320
|
{
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
321
|
+
"forwarders": {
|
|
322
|
+
"example": {
|
|
323
|
+
"host": "example.com",
|
|
324
|
+
"headerTransformations": {
|
|
325
|
+
"send": {
|
|
326
|
+
"source": "/X-Special-Client-Header-Name: (.+)/gi",
|
|
327
|
+
"target": "'New-Header-Name: $1'"
|
|
328
|
+
},
|
|
329
|
+
"retrieve": {
|
|
330
|
+
"source": "/set-cookie: (.+)/gi",
|
|
331
|
+
"target": "'X-Prevented-Cookie: $1'"
|
|
332
|
+
}
|
|
333
|
+
}
|
|
267
334
|
}
|
|
268
|
-
}
|
|
269
335
|
}
|
|
270
|
-
}
|
|
271
336
|
}
|
|
272
337
|
```
|
|
273
338
|
|
|
274
|
-
|
|
275
|
-
|
|
339
|
+
```bash
|
|
340
|
+
curl \
|
|
341
|
+
--header 'X-Special-Client-Header-Name: value' \
|
|
342
|
+
--output /dev/null \
|
|
343
|
+
--verbose \
|
|
344
|
+
http://localhost:8080
|
|
276
345
|
```
|
|
277
|
-
{
|
|
278
|
-
"forwarders": {
|
|
279
|
-
"bing": {
|
|
280
|
-
"host": "www.bing.com",
|
|
281
346
|
|
|
282
|
-
|
|
347
|
+
The backend gets "New-Header-Name: value" and every "set-cookie" header of the
|
|
348
|
+
response arrives as "X-Prevented-Cookie". A transformation without "source"
|
|
349
|
+
adds the header given by "target", e.g.
|
|
350
|
+
"{\"target\": \"'X-Forwarded-By: proxy'\"}". The "host" header is always
|
|
351
|
+
replaced by the backend's host.
|
|
352
|
+
<!--deDE:
|
|
353
|
+
Das Backend erhält "New-Header-Name: value" und jeder
|
|
354
|
+
"set-cookie"-Header der Antwort kommt als "X-Prevented-Cookie" an. Eine
|
|
355
|
+
Transformation ohne "source" fügt den in "target" angegebenen Header
|
|
356
|
+
hinzu, z. B. "{\"target\": \"'X-Forwarded-By: proxy'\"}". Der
|
|
357
|
+
"host"-Header wird immer durch den Host des Backends ersetzt.
|
|
358
|
+
-->
|
|
359
|
+
<!--frFR:
|
|
360
|
+
Le backend reçoit "New-Header-Name: value" et chaque en-tête
|
|
361
|
+
"set-cookie" de la réponse arrive sous la forme "X-Prevented-Cookie".
|
|
362
|
+
Une transformation sans "source" ajoute l'en-tête donné par "target",
|
|
363
|
+
par exemple "{\"target\": \"'X-Forwarded-By: proxy'\"}". L'en-tête
|
|
364
|
+
"host" est toujours remplacé par l'hôte du backend.
|
|
365
|
+
-->
|
|
366
|
+
|
|
367
|
+
### State APIs
|
|
283
368
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
369
|
+
A state API is a request to a third party service which runs before the
|
|
370
|
+
request is forwarded. Its "pre" expressions decide whether it runs, its
|
|
371
|
+
"post" expressions evaluate its response. This forwarder only passes requests
|
|
372
|
+
on if an authentication service accepts their token:
|
|
373
|
+
<!--deDE:
|
|
374
|
+
Eine State-API ist eine Anfrage an einen Dienst eines Drittanbieters,
|
|
375
|
+
die vor dem Weiterleiten der Anfrage läuft. Ihre "pre"-Ausdrücke
|
|
376
|
+
entscheiden, ob sie läuft, ihre "post"-Ausdrücke werten ihre Antwort
|
|
377
|
+
aus. Dieser Forwarder reicht Anfragen nur weiter, wenn ein
|
|
378
|
+
Authentifizierungsdienst ihr Token akzeptiert:
|
|
379
|
+
-->
|
|
380
|
+
<!--frFR:
|
|
381
|
+
Une state API est une requête vers un service tiers qui s'exécute avant
|
|
382
|
+
la transmission de la requête. Ses expressions "pre" décident si elle
|
|
383
|
+
s'exécute, ses expressions "post" évaluent sa réponse. Ce forwarder ne
|
|
384
|
+
transmet les requêtes que si un service d'authentification accepte leur
|
|
385
|
+
jeton:
|
|
386
|
+
-->
|
|
387
|
+
|
|
388
|
+
```JSON
|
|
389
|
+
{
|
|
390
|
+
"forwarders": {
|
|
391
|
+
"example": {
|
|
392
|
+
"host": "example.com",
|
|
393
|
+
"stateAPIs": {
|
|
394
|
+
"name": "authentication",
|
|
395
|
+
"urlExpression": "`https://auth.example.com/check?token=${encodeURIComponent(request.headers['x-token'])}`",
|
|
396
|
+
"options": {"headers": {"accept": "application/json"}},
|
|
397
|
+
"expressions": {
|
|
398
|
+
"pre": "request.headers['x-token'] ? true : 401",
|
|
399
|
+
"post": "stateAPI.response?.ok ? null : 403"
|
|
400
|
+
}
|
|
401
|
+
}
|
|
288
402
|
}
|
|
289
|
-
}
|
|
290
403
|
}
|
|
291
|
-
}
|
|
292
404
|
}
|
|
293
405
|
```
|
|
294
406
|
|
|
295
|
-
|
|
407
|
+
Requests without an "X-Token" header are answered with "401", requests whose
|
|
408
|
+
token the service rejects with "403", all others reach "example.com". The
|
|
409
|
+
service is requested via
|
|
410
|
+
[fetch](https://developer.mozilla.org/docs/Web/API/fetch) with the given
|
|
411
|
+
"options". "url" sets a fixed address instead of
|
|
412
|
+
"urlExpression".
|
|
413
|
+
<!--deDE:
|
|
414
|
+
Anfragen ohne "X-Token"-Header werden mit "401" beantwortet, Anfragen,
|
|
415
|
+
deren Token der Dienst ablehnt, mit "403", alle anderen erreichen
|
|
416
|
+
"example.com". Der Dienst wird über
|
|
417
|
+
[fetch](https://developer.mozilla.org/docs/Web/API/fetch) mit den
|
|
418
|
+
angegebenen "options" angefragt. "url" setzt statt "urlExpression" eine
|
|
419
|
+
feste Adresse.
|
|
420
|
+
-->
|
|
421
|
+
<!--frFR:
|
|
422
|
+
Les requêtes sans en-tête "X-Token" reçoivent "401", celles dont le
|
|
423
|
+
service rejette le jeton "403", toutes les autres atteignent
|
|
424
|
+
"example.com". Le service est interrogé via
|
|
425
|
+
[fetch](https://developer.mozilla.org/docs/Web/API/fetch) avec les
|
|
426
|
+
"options" données. "url" définit une adresse fixe à la place de
|
|
427
|
+
"urlExpression".
|
|
428
|
+
-->
|
|
296
429
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
"
|
|
301
|
-
|
|
430
|
+
"pre" and "post" accept a single expression or a list, which runs in order.
|
|
431
|
+
The result of each "pre" expression means:
|
|
432
|
+
<!--deDE:
|
|
433
|
+
"pre" und "post" akzeptieren einen einzelnen Ausdruck oder eine Liste,
|
|
434
|
+
die der Reihe nach läuft. Das Ergebnis jedes "pre"-Ausdrucks bedeutet:
|
|
435
|
+
-->
|
|
436
|
+
<!--frFR:
|
|
437
|
+
"pre" et "post" acceptent une seule expression ou une liste, exécutée
|
|
438
|
+
dans l'ordre. Le résultat de chaque expression "pre" signifie:
|
|
439
|
+
-->
|
|
302
440
|
|
|
303
|
-
|
|
441
|
+
- "true": run the request of this state API.<!--deDE:"true": die Anfrage dieser State-API ausführen.--><!--frFR:"true": exécuter la requête de cette state API.-->
|
|
442
|
+
- "false": skip this state API and its remaining "pre" expressions.<!--deDE:"false": diese State-API und ihre übrigen "pre"-Ausdrücke überspringen.--><!--frFR:"false": ignorer cette state API et ses expressions "pre" restantes.-->
|
|
443
|
+
- "'break'": stop evaluating "pre" expressions.<!--deDE:"'break'": keine weiteren "pre"-Ausdrücke auswerten.--><!--frFR:"'break'": arrêter d'évaluer les expressions "pre".-->
|
|
444
|
+
- "null" or "undefined": continue with the next expression.<!--deDE:"null" oder "undefined": mit dem nächsten Ausdruck fortfahren.--><!--frFR:"null" ou "undefined": continuer avec l'expression suivante.-->
|
|
445
|
+
- a number: answer the client with this status code and stop.<!--deDE:eine Zahl: dem Client mit diesem Statuscode antworten und abbrechen.--><!--frFR:un nombre: répondre au client avec ce code de statut et s'arrêter.-->
|
|
304
446
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
447
|
+
"post" expressions know the same results except "true" and "false". If no
|
|
448
|
+
expression answers the client, the next state API runs and finally the
|
|
449
|
+
request is forwarded.
|
|
450
|
+
<!--deDE:
|
|
451
|
+
"post"-Ausdrücke kennen dieselben Ergebnisse außer "true" und "false".
|
|
452
|
+
Beantwortet kein Ausdruck den Client, läuft die nächste State-API und
|
|
453
|
+
schließlich wird die Anfrage weitergeleitet.
|
|
454
|
+
-->
|
|
455
|
+
<!--frFR:
|
|
456
|
+
Les expressions "post" connaissent les mêmes résultats sauf "true" et
|
|
457
|
+
"false". Si aucune expression ne répond au client, la state API suivante
|
|
458
|
+
s'exécute et la requête est finalement transmise.
|
|
459
|
+
-->
|
|
315
460
|
|
|
316
|
-
|
|
461
|
+
<!--|deDE:Basis-Konfigurationen-->
|
|
462
|
+
<!--|frFR:Configurations de base-->
|
|
463
|
+
### Base configurations
|
|
317
464
|
|
|
318
|
-
|
|
319
|
-
|
|
465
|
+
Every forwarder inherits from the forwarder "base", and every state API of a
|
|
466
|
+
forwarder inherits from its state API named "base". This configuration
|
|
467
|
+
forwards to two backends under a sub path and asks one service with
|
|
468
|
+
different data depending on the request:
|
|
469
|
+
<!--deDE:
|
|
470
|
+
Jeder Forwarder erbt vom Forwarder "base" und jede State-API eines
|
|
471
|
+
Forwarders von dessen State-API namens "base". Diese Konfiguration
|
|
472
|
+
leitet an zwei Backends unter einem Unterpfad weiter und befragt einen
|
|
473
|
+
Dienst je nach Anfrage mit unterschiedlichen Daten:
|
|
474
|
+
-->
|
|
475
|
+
<!--frFR:
|
|
476
|
+
Chaque forwarder hérite du forwarder "base", et chaque state API d'un
|
|
477
|
+
forwarder hérite de sa state API nommée "base". Cette configuration
|
|
478
|
+
transmet vers deux backends sous un sous-chemin et interroge un service
|
|
479
|
+
avec des données différentes selon la requête:
|
|
480
|
+
-->
|
|
320
481
|
|
|
321
|
-
```
|
|
482
|
+
```JSON
|
|
322
483
|
{
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
484
|
+
"forwarders": {
|
|
485
|
+
"base": {
|
|
486
|
+
"headerTransformations": {
|
|
487
|
+
"send": {
|
|
488
|
+
"source": "/^(GET|POST) \\/(.*) (HTTP.*)$/m",
|
|
489
|
+
"target": "'$1 /sub/path/$2 $3'"
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
},
|
|
493
|
+
"first": {
|
|
494
|
+
"host": "first.example.com",
|
|
495
|
+
"useExpression": "Math.random() < 0.5"
|
|
496
|
+
},
|
|
497
|
+
"second": {
|
|
498
|
+
"host": "second.example.com",
|
|
499
|
+
"stateAPIs": [
|
|
500
|
+
{
|
|
501
|
+
"name": "base",
|
|
502
|
+
"urlExpression": "`https://service.example.com/?q=${data.query}`",
|
|
503
|
+
"expressions": {
|
|
504
|
+
"pre": "request.headers[data.header] ? true : null",
|
|
505
|
+
"post": "stateAPI.response?.data?.allowed ? null : 403"
|
|
506
|
+
}
|
|
507
|
+
},
|
|
508
|
+
{
|
|
509
|
+
"name": "cats",
|
|
510
|
+
"data": {"header": "x-cats", "query": "cats"}
|
|
511
|
+
},
|
|
512
|
+
{
|
|
513
|
+
"name": "dogs",
|
|
514
|
+
"data": {"header": "x-dogs", "query": "dogs"}
|
|
515
|
+
}
|
|
516
|
+
]
|
|
517
|
+
}
|
|
327
518
|
}
|
|
328
|
-
}
|
|
329
519
|
}
|
|
330
520
|
```
|
|
331
521
|
|
|
332
|
-
|
|
522
|
+
"data" holds any values for the expressions. JSON responses of state APIs are
|
|
523
|
+
available as "stateAPI.response.data".
|
|
524
|
+
<!--deDE:
|
|
525
|
+
"data" enthält beliebige Werte für die Ausdrücke. JSON-Antworten von
|
|
526
|
+
State-APIs stehen als "stateAPI.response.data" zur Verfügung.
|
|
527
|
+
-->
|
|
528
|
+
<!--frFR:
|
|
529
|
+
"data" contient des valeurs quelconques pour les expressions. Les
|
|
530
|
+
réponses JSON des state APIs sont disponibles sous
|
|
531
|
+
"stateAPI.response.data".
|
|
532
|
+
-->
|
|
333
533
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
"__evaluate__": "environment.PORT ?? 8080"
|
|
338
|
-
},
|
|
339
|
-
...
|
|
340
|
-
}
|
|
341
|
-
```
|
|
534
|
+
<!--|deDE:Ausdrücke-->
|
|
535
|
+
<!--|frFR:Expressions-->
|
|
536
|
+
### Expressions
|
|
342
537
|
|
|
343
|
-
|
|
344
|
-
|
|
538
|
+
Every expression is a JavaScript expression with access to:
|
|
539
|
+
<!--deDE:Jeder Ausdruck ist ein JavaScript-Ausdruck mit Zugriff auf:-->
|
|
540
|
+
<!--frFR:Chaque expression est une expression JavaScript ayant accès à:-->
|
|
345
541
|
|
|
346
|
-
|
|
542
|
+
- "request": the client request with "url", "method" and "headers".<!--deDE:"request": die Client-Anfrage mit "url", "method" und "headers".--><!--frFR:"request": la requête du client avec "url", "method" et "headers".-->
|
|
543
|
+
- "response": the response to the client (not the one of a state API).<!--deDE:"response": die Antwort an den Client (nicht die einer State-API).--><!--frFR:"response": la réponse au client (pas celle d'une state API).-->
|
|
544
|
+
- "stateAPI": the current state API with its "configuration", "error" and "response".<!--deDE:"stateAPI": die aktuelle State-API mit "configuration", "error" und "response".--><!--frFR:"stateAPI": la state API courante avec "configuration", "error" et "response".-->
|
|
545
|
+
- "stateAPIs": all state APIs of the forwarder by name, e.g. in header transformations.<!--deDE:"stateAPIs": alle State-APIs des Forwarders nach Namen, z. B. in Header-Transformationen.--><!--frFR:"stateAPIs": toutes les state APIs du forwarder par nom, par exemple dans les transformations d'en-têtes.-->
|
|
546
|
+
- "data": the state API's "data", the forwarder in "useExpression" and both sockets in header transformations.<!--deDE:"data": die "data" der State-API, der Forwarder in "useExpression" und beide Sockets in Header-Transformationen.--><!--frFR:"data": les "data" de la state API, le forwarder dans "useExpression" et les deux sockets dans les transformations d'en-têtes.-->
|
|
547
|
+
- "error": the error of a failed state API request.<!--deDE:"error": der Fehler einer fehlgeschlagenen State-API-Anfrage.--><!--frFR:"error": l'erreur d'une requête de state API échouée.-->
|
|
548
|
+
- "array", "datetime", "object", "string", "utility" and more: helpers of [clientnode](https://tsickert.com/clientnode).<!--deDE:"array", "datetime", "object", "string", "utility" und mehr: Hilfsfunktionen von [clientnode](https://tsickert.com/clientnode).--><!--frFR:"array", "datetime", "object", "string", "utility" et d'autres: fonctions utilitaires de [clientnode](https://tsickert.com/clientnode).-->
|
|
347
549
|
|
|
348
|
-
|
|
550
|
+
For example, this send transformation passes the answer of the
|
|
551
|
+
authentication service from above on to the backend:
|
|
552
|
+
<!--deDE:
|
|
553
|
+
Diese Send-Transformation gibt zum Beispiel die Antwort des
|
|
554
|
+
Authentifizierungsdienstes von oben an das Backend weiter:
|
|
555
|
+
-->
|
|
556
|
+
<!--frFR:
|
|
557
|
+
Par exemple, cette transformation "send" transmet au backend la réponse
|
|
558
|
+
du service d'authentification ci-dessus:
|
|
559
|
+
-->
|
|
349
560
|
|
|
350
|
-
```
|
|
561
|
+
```JSON
|
|
351
562
|
{
|
|
352
|
-
|
|
353
|
-
"base: {
|
|
354
|
-
"headerTransformations": {
|
|
355
|
-
"send": {
|
|
356
|
-
"source": "/(GET|POST) \\/.* (.*)/",
|
|
357
|
-
"target": "'$1 /sub/path/to/forward/to $2'"
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
},
|
|
361
|
-
|
|
362
|
-
"bing": {
|
|
363
|
-
"host": "www.bing.com",
|
|
364
|
-
"useExpression": "Math.random() < 0.5"
|
|
365
|
-
},
|
|
366
|
-
|
|
367
|
-
"google": {
|
|
368
|
-
"host": "www.google.com"
|
|
369
|
-
}
|
|
370
|
-
}
|
|
563
|
+
"target": "`X-Allowed: ${stateAPIs.authentication.response?.data?.allowed}`"
|
|
371
564
|
}
|
|
372
565
|
```
|
|
373
566
|
|
|
374
|
-
|
|
567
|
+
<!--|deDE:Einzelwerte oder Listen-->
|
|
568
|
+
<!--|frFR:Valeurs uniques ou listes-->
|
|
569
|
+
### Single values or lists
|
|
375
570
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
571
|
+
"headerTransformations.send", "headerTransformations.retrieve", "stateAPIs",
|
|
572
|
+
"expressions.pre" and "expressions.post" take a single item or a list of
|
|
573
|
+
items. "{...}" means the same as "[{...}]".
|
|
574
|
+
<!--deDE:
|
|
575
|
+
"headerTransformations.send", "headerTransformations.retrieve",
|
|
576
|
+
"stateAPIs", "expressions.pre" und "expressions.post" nehmen ein
|
|
577
|
+
einzelnes Element oder eine Liste von Elementen. "{...}" bedeutet
|
|
578
|
+
dasselbe wie "[{...}]".
|
|
579
|
+
-->
|
|
580
|
+
<!--frFR:
|
|
581
|
+
"headerTransformations.send", "headerTransformations.retrieve",
|
|
582
|
+
"stateAPIs", "expressions.pre" et "expressions.post" acceptent un seul
|
|
583
|
+
élément ou une liste d'éléments. "{...}" signifie la même chose que
|
|
584
|
+
"[{...}]".
|
|
585
|
+
-->
|
|
383
586
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
"target": "'$1 /sub/path/to/forward/to $2'"
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
},
|
|
587
|
+
<!--|deDE:Umgebungsvariablen-->
|
|
588
|
+
<!--|frFR:Variables d'environnement-->
|
|
589
|
+
### Environment variables
|
|
391
590
|
|
|
392
|
-
|
|
393
|
-
|
|
591
|
+
Any value of the configuration can be computed once on start with
|
|
592
|
+
"__evaluate__", which has access to "environment" and "configuration":
|
|
593
|
+
<!--deDE:
|
|
594
|
+
Jeder Wert der Konfiguration lässt sich beim Start einmalig über
|
|
595
|
+
"__evaluate__" berechnen, das Zugriff auf "environment" und
|
|
596
|
+
"configuration" hat:
|
|
597
|
+
-->
|
|
598
|
+
<!--frFR:
|
|
599
|
+
Toute valeur de la configuration peut être calculée une fois au
|
|
600
|
+
démarrage via "__evaluate__", qui a accès à "environment" et
|
|
601
|
+
"configuration":
|
|
602
|
+
-->
|
|
394
603
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
604
|
+
```JSON
|
|
605
|
+
{
|
|
606
|
+
"forwarders": {
|
|
607
|
+
"example": {
|
|
608
|
+
"host": {
|
|
609
|
+
"__evaluate__": "environment.BACKEND_HOST ?? 'example.com'"
|
|
610
|
+
}
|
|
399
611
|
}
|
|
400
|
-
}
|
|
401
612
|
}
|
|
402
|
-
}
|
|
403
613
|
}
|
|
404
614
|
```
|
|
405
615
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
"name": "base",
|
|
420
|
-
"url": "https://www.google.com/search?q=${data.query}",
|
|
421
|
-
|
|
422
|
-
"expressions": {
|
|
423
|
-
"pre": "request.headers['ask-google'] ? true : null",
|
|
424
|
-
"post": "response.statusCode >= 200 && response.statusCode < 300 ? null : response.statusCode"
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
{
|
|
429
|
-
"name": "sense",
|
|
430
|
-
|
|
431
|
-
"data": {
|
|
432
|
-
"query": "What is the meaning of life?"
|
|
433
|
-
}
|
|
434
|
-
},
|
|
616
|
+
The proxy then forwards to the host given in the environment variable
|
|
617
|
+
"BACKEND_HOST" or to "example.com". The default "port" works the same way
|
|
618
|
+
with "PORT".
|
|
619
|
+
<!--deDE:
|
|
620
|
+
Der Proxy leitet dann an den in der Umgebungsvariable "BACKEND_HOST"
|
|
621
|
+
angegebenen Host weiter oder an "example.com". Der Standardwert von
|
|
622
|
+
"port" funktioniert genauso mit "PORT".
|
|
623
|
+
-->
|
|
624
|
+
<!--frFR:
|
|
625
|
+
Le proxy transmet alors à l'hôte donné dans la variable d'environnement
|
|
626
|
+
"BACKEND_HOST" ou à "example.com". La valeur par défaut de "port"
|
|
627
|
+
fonctionne de la même façon avec "PORT".
|
|
628
|
+
-->
|
|
435
629
|
|
|
436
|
-
|
|
437
|
-
|
|
630
|
+
<!--|deDE:Entwicklung-->
|
|
631
|
+
<!--|frFR:Développement-->
|
|
632
|
+
Development
|
|
633
|
+
-----------
|
|
438
634
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
}
|
|
635
|
+
```bash
|
|
636
|
+
yarn install
|
|
637
|
+
yarn check
|
|
638
|
+
yarn test
|
|
639
|
+
yarn serve:simple
|
|
447
640
|
```
|
|
448
641
|
|
|
449
|
-
|
|
450
|
-
"
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
| response | Response informations (available in post evaluations). |
|
|
464
|
-
| stateAPIs | Access oher state api informations. |
|
|
465
|
-
| Tools | [see](https://www.npmjs.com/package/clientnode) |
|
|
642
|
+
"yarn check" checks types and lints, "yarn serve:<name>" builds the
|
|
643
|
+
proxy and starts it with one of the configurations in "examples/" ("headers",
|
|
644
|
+
"random", "simple" or "state-apis").
|
|
645
|
+
<!--deDE:
|
|
646
|
+
"yarn check" prüft Typen und lintet, "yarn serve:<name>" baut den
|
|
647
|
+
Proxy und startet ihn mit einer der Konfigurationen in "examples/"
|
|
648
|
+
("headers", "random", "simple" oder "state-apis").
|
|
649
|
+
-->
|
|
650
|
+
<!--frFR:
|
|
651
|
+
"yarn check" vérifie les types et lance le linter, "yarn
|
|
652
|
+
serve:<name>" construit le proxy et le lance avec l'une des
|
|
653
|
+
configurations de "examples/" ("headers", "random", "simple" ou
|
|
654
|
+
"state-apis").
|
|
655
|
+
-->
|