This is a viewer only at the moment see the article on how this works.
To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk
This is a preview from the server running through my markdig pipeline
StyloBot Release Series - Die Sidecar-Architektur
Monday, 01 June 2026
StyloBot-'-Detektions-Engine ist ASP..-NET Core-MSC2-Dieser Beitrag erklärt, wie dieser Motor mit Go Gateways verbunden ist.,-Node-.-js-Anwendungen. ,- und jeder andere Stapel über einen gRPC Sidecar.MSC6- ein typisiertes Go SDKK7- und ein Caddy-Plugin, ohne dass die Verbraucher etwas über die internen Systeme von .-NET wissen müssen.
Das
github.com/scottgal/stylobot-goSDK-,- dasgithub.com/scottgal/caddy-stylobotplugin-,- und dieMostlylucid.BotDetection.SidecarContainer wird in Kürze veröffentlicht Alles unten beschreibt die Oberfläche, die sie aussetzen werden
StyloBot Release Series
- Verhalten nicht IdentitätWarum StyloBot die Kunden verhaltensmäßig modelliert
- Verhalten Bewusst WERDENDie Server-Oberfläche von -, die für Anwendungen von . oder NET bestimmt ist
- Ungebundenes Wachstum in langen --Diensten finden und behebenDie Zuverlässigkeitsdisziplin, die den Motor in der Produktion langweilig hält
- Verhalten--Bewusstsein TypScript UIKomponenten von , und Browsern
- Die Sidecar-ArchitekturDieser Artikel
- Schneller lernenDas adaptive Lernsystem (MSK) und der Urteilscache
- Testen der Sache, die Won-' sitt StillEine BDF-Datei treibt Regression an.
- StyloExtrahieren Sie einen lokalen HTML zu Markdown KonverterDie HTML-Markdown-Schicht, die sich mit dem Detektor verbindet, hat den Walker Bug lucidVIEW gefangen und die Hundefutterschleife, die es ehrlich machte.
Warum ein Beiwagen?
Ein umgekehrter Proxy ist der offensichtliche Ort, um Bot-Detektion zu starten.:. Er sitzt vor allem und sieht jede Anfrage und kann blocken bevor jeder Anwendungscode läuft.MSC3. Diese Logik hält richtig, bis Sie fragen, was Ihre Anwendung sollte anders machen based on who is make the request- - ein Gateway, das direkt blockiert ist ein gate- -;-, was die meisten Anwendungen tatsächlich brauchen, ist ein Urteil können sie auf mehrere Weisen sofort handeln - : drosseln die API-,-Personalisierung der UI-MSC4-exclude Traffic aus analytics - ,- fügen Sie einen Reibungsschritt bei Checkout-.-Ein Gate kann nichts von dem tun - . - Ein Urteil Pipeline can -MSC8-
Das Sidecar-Muster trennt die beiden Belange.Das Gateway bleibt schnell und staatenlos.Das Sidecar hält den Sitzungszustand aufrecht., archetype anker, , drift state,, quitting cache, das die Detektion präzise macht. Schneller lernenDie beiden kommunizieren über das lokale Netzwerk .. . .(samer Host oder gleiches Pod... so ist der runde -" Trip Mikrosekunden zu einzelnen -"stelligen Millisekunden " . ," nicht die . 50-200"ms eines entfernten API-Aufrufs " .. Das Latenzbudget ist, was per... -"Erkennung praktisch macht .
Dies ist kein neuartiges Muster. Gesandter Proxy tut genau dies für den Dienst ,- ,mesh betrifft , ( , mTLS , , , Retries , ., , Stromkreisbruch , Dapr tut es für Zustand und pub-/-sub OpenTelemetrie Sammler does it for telemetry- - .-Linkerd-,-Consul Connect- und AWS App Mesh folgen alle dem gleichen Modell. Das Muster erscheint immer, weil es ein echtes Problem löst.: - Sie wollen komplexe stateful Verhalten, das Sprachgrenzen überschreitet, ohne es in jeder Sprache umzuimplementieren.
Warum nicht einfach als Bibliothek einbetten?
Die Alternative ist das Kompilieren von Detektion direkt in die Gateway-Bibliothek, d.h. eine reine Pressemitteilung oder eine CGo-Bindung an eine C-Bibliothek.
Ebenso wenig ist realistisch für einen Motor dieser Komplexität... StyloBot hat über vier Ausführungs-Detektoren organisiert. Wellen (-spätere Wellen feuern nur dann, wenn frühere Signale es rechtfertigen. ;-skalierender Versuch löst andere Detektoren aus als ein Googlebot crawling. Markov-Kettenvektoren Eine Markov-Kette ist nur ein Wahrscheinlichkeitsmodell über ", gegeben das letzte, was diese Sitzung getan hat,, was als nächstes kommt?", und 129, Dimensionen erfasst genug Seite-, transition Form Menschen zu sagen und Bots auseinander ., Es läuft Nachweis der Leiden-Gemeinschaft über die Vektoren ,: , ein Graph , - , Clustering-Algorithmus , dass Gruppen Sitzungen gleichen Verhaltens , , , das ist wie StyloBot ein Bot-Netzwerk auch wenn einzelne Sessions fein aussehen , und es bleibt all dies auf SQLite zwischen Anfragen ,. , Dieser Zustand braucht einen unabhängigen Lebenszyklus .. , Es kann nicht mit dem Knoten-Prozess neu starten oder abgerissen werden, wenn das Gateway reloads seine Konfiguration , . ,
Ein Sidecar lässt jede Komponente tun, was es gut ist
graph TD
classDef input fill:none,stroke:#3b82f6,stroke-width:2px
classDef async fill:none,stroke:#a855f7,stroke-width:2px
classDef good fill:none,stroke:#22c55e,stroke-width:2px
classDef store fill:none,stroke:#f59e0b,stroke-width:2px
GW["Gateway<br/>Caddy / YARP / nginx"]:::input
SD["StyloBot Sidecar · ASP.NET Core<br/>gRPC :5090 · REST :5091<br/>≤50ms per Detect RPC"]:::async
APP["Upstream Application<br/>Node / Go / ASP.NET<br/>reads req.stylobot.verdict"]:::good
DB[("SQLite<br/>sessions · signatures · reputation")]:::store
GW --> SD
SD <--> DB
GW --> APP
Das Gateway ruft den Sidecar auf und injiziert das Ergebnis als HTTP-Header.,. Optional blockiert die Upstream-Anwendung die Header und wirkt nach dem Urteil.MS K3. Das Sidecar hält an Zustand zwischen Anfragen... Die Detektionspipeline läuft innerhalb des einzelnen gRPC-Aufrufs und sein Ergebnis propagiert sich als neun HTTP-Kopfzeilen.
Der Beiwagen
Mostlylucid.BotDetection.Sidecar ist ein minimaler ASP-.-NET-Kernprozess, der keine UI-MSC2 ist, keine statische Datei dient und kein Routing über die Endpunkte gRPC und REST hinaus verfügt. Es startet den Volldetektionsmotor und setzt zwei Ports aus.
- :5090HTTP®/2 für gRPC-Clients ( gateways, , gehen Proxies, , der Knoten gRPc-Client ) ,
- :5091HTTP-Ausfuhr für REST-Clients
/api/v1/*Endpunkte
gRPC
gRPC ist ein hochleistungsfähiges Remote-Procedure-Call Framework, das bei Google entwickelt wurde. Protokollpuffer Eine kompakte binäre Kodierung, die schneller zu Serialisierung und kleiner auf dem Draht ist als JSON-.. gRPC läuft über HTTP./2,, was bedeutet, dass es Multiplexing Mehrfache Anfragen über eine TCP-Verbindung erhält.
Die Schnittstelle ist in einem .proto aus dieser Datei erzeugen typisierte Client- und Server-Stubs in jeder unterstützten Sprache. .proto Dateien, so dass jede Sprache mit einer gRPC-Implementierung das Sidecar nennen kann.
Die gRPC-Schnittstelle
Der Dienst hat drei RPCs.
service DetectionService {
rpc Detect(DetectRequest) returns (DetectResponse);
rpc DetectBatch(DetectBatchRequest) returns (DetectBatchResponse);
rpc RenderWidget(RenderWidgetRequest) returns (RenderWidgetResponse);
}
Detect ist der per---Request-Hot Path?.-Pass es Methode ,,-Pfad , ,-Header , ,-Remote IP , und optional TLS Fingerabdruckdaten , .-Es läuft die Welle Pipeline nur die Detektoren, dass die Anfrage ,'-Signale Warrant , die Sitzung vector , ,-Scores gegen den Reputation Store .,- und gibt ein Urteil ,
DetectBatch läuft mehrere Anfragen sequentiell ,. , verwendet für Protokoll-Wiedergabe und Offline-Analyse , , , nicht per , - , anfordern Gateway verwenden .. ,
RenderWidget akzeptiert eine Liquid-Schablone-String-Strings-,, ein optionales Urteilsurteil und eine Schlüsselkarte von zusätzlichen Variablen.,, macht dann den Vorlagenserver wieder und gibt HTML.MSC5 zurück.Dies ist die Art und Weise, wie Nicht-MSC6-NET-Anrufer Bot?-aware-HTML produzieren, ohne einen separaten Renderprozess aufzustellen.;, Details im Abschnitt RenderWidget weiter unten.
Was in einem Detect-Anruf passiert
Ein schnelles Glossar vor dem Diagramm, da diese Namen erscheinen werden.
- Tafel:, ein Per--, Schlüssel anfordern -, Wertbeutel, ., g.
request.ip.is_datacenter,detection.useragent.confidenceDetektoren schreiben Signale zu ihr;. Spätere Detektor in der gleichen Welle lesen sie.. Lebt nur für die Dauer einer Anfrage und landet nie auf der Tafel... - Synthetisch HttpKontext:" ein Ständer ,-"in
HttpContextder gRPC-Service baut aus den proto request fields. Die Detektionsmaschine wurde für ASP ,.'NET Middleware entwickelt und erwartet vonHttpContextDie Synthese lässt den gleichen Motor in einem gRPC-Ruf unverändert laufen. - NachweisBeiträge / Aggregierte EvidenzDetektorausgänge ( signal schreibt Vertrauen Deltas ) und ihr zusammengeführtes Ergebnis .
sequenceDiagram
participant GW as Gateway (Caddy)
participant SD as gRPC Service
participant ORC as BlackboardOrchestrator
participant DET as Detectors (up to 49, 4 waves)
participant DB as SQLite
GW->>SD: Detect RPC { method, path, headers, remoteIp }
SD->>ORC: DetectAsync(syntheticHttpContext)
ORC->>DET: Wave 0 - Identity + ContentSequence
ORC->>DET: Wave 1 - Fast path <1ms: UA, Header, IP, Heuristic ...
ORC->>DET: Wave 2 - Session vectors, Behavioural waveform
ORC->>DET: Wave 3 - Slow path: DNS, advanced fingerprinting
DET-->>ORC: DetectionContributions (signals, confidence deltas)
ORC->>DB: update session vector and reputation score
DB-->>ORC: ok
ORC-->>SD: AggregatedEvidence { botProbability, riskBand, ... }
SD-->>GW: DetectResponse { isBot, riskBand, recommendedAction, ... }
Die gesamte Pipeline läuft innerhalb des einzelnen gRPC-Aufrufs...Es gibt keine Async-Arbeit, nachdem die Antwort zurückgegeben wurde.
Das Go SDK
Gateway-Code in Go kann nicht importieren, die ASP .. .NET Sidecar ?. . Was es tun kann, ist es über gRPC nennen .github.com/scottgal/stylobot-go-) , bietet eine getippte Schnittstelle, die die erzeugten Protobuf Typen von Anrufern vollständig versteckt
Warum das SDK Protobuf Typen versteckt
Protobuf---generierter Code ist verbose und hat eine ungewöhnliche API..-Enums werden als Integer dargestellt.MSC2-Strings kommen als rohe proto enum Namen.RISK_BAND_HIGHNicht "High"Feldnamen sind Kamelfall in einigen Generatoren und Schlangenfall in anderen Ausstellen von Prototypen in Ihrer öffentlichen API bedeutet, dass Ihre Anrufer all dies verstehen müssen
Das SDK übersetzt einmal an der Grenze .( enums to canonical strings . , . proto structs to plain Go stucts ,) . und Anrufer nie sehen es .
// the only interface you depend on: no proto imports required
type Client interface {
Detect(ctx context.Context, req DetectRequest) (*Verdict, error)
DetectBatch(ctx context.Context, reqs []DetectRequest) ([]*Verdict, error)
RenderWidget(ctx context.Context, req RenderRequest) (*RenderResponse, error)
Close() error
}
DetectRequest und Verdict sind einfache Go-Strukturen
type DetectRequest struct {
Method string
Path string
Headers map[string]string
RemoteIP string
Protocol string // "http" or "https"; defaults to "https" if empty
TLS *TLSInfo
}
type Verdict struct {
IsBot bool
BotProbability float32
Confidence float32
BotType string // "AiBot", "Scraper", "GoodBot", ...
BotName string
RiskBand string // "VeryLow", "Low", "Elevated", "Medium", "High", "VeryHigh"
RecommendedAction string // "Allow", "Throttle", "Challenge", "Block"
ThreatScore float32
ThreatBand string
ProcessingTimeMs float32
DetectorsRun int32
Reasons []Reason
}
Erstellen eines Clients und laufende Erkennung
import (
stylobot "github.com/scottgal/stylobot-go"
"context"
"time"
)
client, err := stylobot.NewClient(
"localhost:5090",
stylobot.WithTimeout(50 * time.Millisecond),
stylobot.WithAPIKey(os.Getenv("SB_API_KEY")),
)
if err != nil {
log.Fatal(err)
}
defer client.Close()
verdict, err := client.Detect(ctx, stylobot.DetectRequest{
Method: r.Method,
Path: r.URL.RequestURI(),
RemoteIP: r.RemoteAddr,
Headers: extractHeaders(r),
Protocol: "https",
})
if err != nil {
// fail open: log and continue
log.Printf("stylobot detect failed: %v", err)
return next(w, r)
}
if verdict.RecommendedAction == "Block" {
http.Error(w, "Forbidden", http.StatusForbidden)
return
}
Lazy Verbindung und Startsicherheit
grpc.NewClient erstellt einen Client-Kanal, baut aber nicht sofort eine TCP-Verbindung auf Die Verbindung erfolgt beim ersten RPC-Anruf .. . Dies bedeutet, dass Ihr Gateway-Prozess erfolgreich startet, auch wenn das Sidecar noch nicht gestartet ist . . . Die erste Anfrage nach dem Start kann fehlschlagen .( . und sollte mit failant behandelt werden .
Dies unterscheidet sich von HTTP-Clients, in denen Sie typischerweise bei der Erstellung verbinden. gRPC Go Dokumentation deckt den Lebenszyklus im Detail ab
Timeout-Interaktion
WithTimeout am NewClient setzt eine Standard-Per---Call-Deadline, die in jedem Detect call-.-Wenn Ihr aufrufender Code ( oder Middleware wie das Caddy-Plugin )- bereits eine Frist ableitet, die von der eingehenden Anfrage , eingeblendet wird, gilt das SDK, welche Frist zuerst abläuft..-Wenn das Cadody-Plugin verwendet wird, kann das Plugin die Frist 50-ms nicht mehr verwenden. WithTimeout von NewClient und lassen Sie das Plugin es steuern...... Für den Standalone-Einsatz....... ein Handler, der das SDK direkt anruft.... NewClient wie oben gezeigt
Das Caddy-Modul
Caddy ist ein Go®--basierter Webserver und Reverse Proxy mit automatischer HTTPS®MS K1. Sein Plugin-System wird kompiliert.-?time?:? xcaddy um eine benutzerdefinierte Caddy-Binärdatei zu erstellen, die Ihre Plugins enthält, die ein einziges selbst produzierendes Binärmodul ohne Laufzeitabhängigkeit von geteilten Bibliotheken erzeugen, das sich von dem dynamischen Modulsystem nginx-' unterscheidet..so Dateien, die zur Laufzeit geladen werden... das StyloBot-Plugin...github.com/scottgal/caddy-stylobot) registriert einen Middleware-Handler, der das Go SDK auf jede Anfrage ruft
Die Konfiguration der Caddyfiles
{
order stylobot before respond
}
:80 {
stylobot {
endpoint localhost:5090 # gRPC host:port of the sidecar
timeout 50ms # per-request deadline; fails open on expiry
# on_block 503 # optional: change the block status code (default: 403)
}
reverse_proxy upstream:3000
}
Das Plugin injiziert neun Urteil-Header auf jede übermittelte Anfrage.
Quelle Feld
|---|---|
| X-StyloBot-IsBot | isBot (-Bool-)-|-
| X-StyloBot-Probability | botProbability (0.0-1.0) |
| X-StyloBot-Confidence | confidence (0.0-1.0) |
| X-StyloBot-BotType |" e-, ." g, ,." AiBot, Scraper, GoodBot |
| X-StyloBot-BotName |" e-, ." g, ,." GPTBot, Googlebot |
| X-StyloBot-RiskBand | VeryLow ... VeryHigh |
| X-StyloBot-Action | Allow / Throttle / Challenge / Block |
| X-StyloBot-ThreatScore ,| , numerisch , |
| X-StyloBot-ThreatBand | None ... Critical |
Anträge auf isBot=true und Action=Block werden am Gateway mit einem 403 stoppt und erreichen nie die vorgelagerten ., alles andere, einschließlich Bots mit Throttle oder Challenge Empfehlung: Das Gateway wird mit allen neun Headern intakt weitergeleitet.Das ist der beabsichtigte Split. Das Gateway verarbeitet harte Blöcke.
on_block ändert den Statuscode, der verwendet wird, wenn das Gateway blockiert. on_block 503 zu unterdrücken retry Logik in Schabern, die als wiederverwendbar behandeln
Was die Middleware auf jede Anfrage macht
flowchart TD
classDef input fill:none,stroke:#3b82f6,stroke-width:2px
classDef async fill:none,stroke:#a855f7,stroke-width:2px
classDef good fill:none,stroke:#22c55e,stroke-width:2px
A["1. Strip inbound X-StyloBot-* headers"]:::input
B["2. context.WithTimeout(r.Context(), 50ms)"]:::input
C["3. sbClient.Detect(ctx, DetectRequest)"]:::async
D{error?}
E["log warn - fail open<br/>forward unchanged"]:::good
F["4. injectHeaders<br/>X-StyloBot-IsBot, Probability, Confidence,<br/>BotType, BotName, RiskBand, Action,<br/>ThreatScore, ThreatBand"]:::input
I["next.ServeHTTP - forward to upstream<br/>with all verdict headers injected"]:::good
A --> B --> C --> D
D -->|yes| E --> I
D -->|no| F --> I
Schritt - Streifen inbound Kopfzeilen Ein Kunde, der die X-StyloBot-* Header-Namen konnten sich selbst aussenden ein günstiges Urteil und haben es überleben die fail-?open path .? Stripping sie zuerst bedeutet das Urteil der Upstream sieht immer aus dem Sidecar?.?
Schritt: Kontext-Deadline Der Timeout ist abgeleitet von r.Context() Verwendung context.WithTimeout .( , die eine relative Dauer dauert . context.WithDeadline nimmt eine absolute Zeit... sie sind äquivalent... r.Context() eher als context.Background() ist der Schlüsselpunkt, wenn sich der Client vor dem gRPC-Aufruf trennt und die Absage propagiert und das Sidecar die Verarbeitung vorzeitig beendet.
Schritte 3 und 4, erkennen und injizieren Die neun Urteilsfelder werden zu neun X-StyloBot-* headers-.-Header werden vor dem Blockcheck gesetzt, also liest der Upstream sie über styloBotMiddleware({ mode: 'headers' }) für alle nicht geblockten Anfragen isBot=true und recommendedAction=Block werden am Gateway als 403 zurückgegeben, alles andere vorwärts mit den vollständigen Urteil-Headern angehängt.
Die Implementierung
// from sdk/caddy/stylobot.go
func (s *StyloBot) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
for _, name := range stylobotHeaders {
r.Header.Del(name)
}
ctx, cancel := context.WithTimeout(r.Context(), s.timeout)
defer cancel()
verdict, err := s.sbClient.Detect(ctx, sb.DetectRequest{
Method: r.Method,
Path: r.URL.RequestURI(),
RemoteIP: ExtractIP(r),
Protocol: r.Proto,
Headers: ExtractHeaders(r),
})
if err != nil {
s.logger.Warn("stylobot detect failed, failing open", zap.Error(err))
return next.ServeHTTP(w, r)
}
injectHeaders(r, verdict)
if verdict.IsBot && s.OnBlock > 0 && verdict.RecommendedAction == "Block" {
http.Error(w, "Forbidden", s.OnBlock)
return nil
}
return next.ServeHTTP(w, r)
}
Gebäude mit xcaddy
Caddy-Plugins müssen in die binäre kompiliert werden xcaddyDas Dockerfile in den Integrationstests zeigt das Muster.
# from tests/integration/caddy-sidecar/Dockerfile
FROM caddy:2-builder AS builder
WORKDIR /build
COPY sdk/caddy/ caddy-plugin/
COPY sdk/go/ go/
WORKDIR /build/caddy-plugin
RUN xcaddy build \
--with github.com/scottgal/caddy-stylobot=/build/caddy-plugin \
--with github.com/scottgal/stylobot-go=/build/go
FROM caddy:2
COPY --from=builder /build/caddy-plugin/caddy /usr/bin/caddy
COPY tests/integration/caddy-sidecar/Caddyfile /etc/caddy/Caddyfile
Die xcaddy-Richtlinie wird ersetzt
Das Plugin„'" go.mod enthält:
replace github.com/scottgal/stylobot-go => ../go
Dies sagt die Go-Toolchain, wenn Sie sehen stylobot-goVerwenden Sie das lokale Verzeichnis, anstatt aus dem Modul Proxy zu holen. Es funktioniert für go build und go test im Plugin-Verzeichnis
xcaddy erstellt ein frisches temporäres Go-Modul für sein build-.-Das Modul erbt nicht replace Direktiven aus dem Plugin go.modOhne die zweite --with Argument: xcaddy würde versuchen, herunterladen stylobot-go von pkg.go.dev (, wo es noch nicht veröffentlicht wird, ) und fail-.
Das --with module=path argument ist xcaddy.'.s natives Äquivalent einer replace Direktive: : , es zeigt einen Modulpfad zu einem lokalen Verzeichnis zum Zeitpunkt des Erstellens an.. , Beide lokale Module müssen explizit benannt werden.
RenderWidget-:® Flüssige Vorlagen über gRPC
RenderWidget ist ein gRPC RPC auf dem Sidecar, der eine Liquid-Schablone-String akzeptiert, das es mit dem Erkennungskontext rendert,, und HTML-Street zurückgibt.Dies erlaubt jedem Anrufer einen Proxy ,, Node SSR Layer,, Batch Pipeline ), Bot--aware-HTML zu produzieren ohne einen separaten Renderprozess auszuführen..
Flüssige Vorlagen
flüssig ist eine templating Sprache, die von Shopify erstellt wurde., used by Shopify themes............... und viele andere Systeme...... seine wichtigsten Eigenschaften...... sicher mit Benutzer zu laufen...... ...-... mitgelieferte Vorlagen...... keine willkürliche Code-Ausführung...... ..),... einfach genug für Nicht---Entwickler zum Schreiben...... Fluid-.-KörnerEine hohe Leistung von - ist die Implementierung von Liquid-, zum Rendern von Vorlagen.
Die Sidecar-Implementierung
// from src/Mostlylucid.BotDetection.Sidecar/Services/DetectionGrpcService.cs
private static readonly FluidParser Parser = new(); // static, shared, compiled templates cached
public override async Task<Proto.RenderWidgetResponse> RenderWidget(
Proto.RenderWidgetRequest request, ServerCallContext context)
{
if (!Parser.TryParse(request.Template, out var template, out var error))
return new Proto.RenderWidgetResponse { Success = false, Error = error };
var ctx = new TemplateContext();
if (request.Verdict is { } v)
{
ctx.SetValue("isBot", v.IsBot);
ctx.SetValue("botProbability", (double)v.BotProbability);
ctx.SetValue("botType", v.BotType);
ctx.SetValue("botName", v.BotName);
ctx.SetValue("riskBand", v.RiskBand.ToString());
ctx.SetValue("recommendedAction", v.RecommendedAction.ToString());
ctx.SetValue("threatScore", (double)v.ThreatScore);
ctx.SetValue("threatBand", v.ThreatBand.ToString());
}
foreach (var kv in request.Vars)
ctx.SetValue(kv.Key, kv.Value);
var html = await template.RenderAsync(ctx);
return new Proto.RenderWidgetResponse { Html = html, Success = true };
}
Fluid-.-Core pflegt einen internen kompilierten Vorlagencache... Wiederholte Renders des gleichen Template-Strings überspringen re...-.parsing ?.. FluidParser ist statisch und über alle gRPC-Aufrufe verteilt
Der Knoten StyloBotGrpcClient.renderWidget() Beispiel und die vollständige Vorlage Variable Referenz sind in der TypeScript SDK Artikel.
Ich rufe es von Go-:.
rendered, err := client.RenderWidget(ctx, stylobot.RenderRequest{
Template: `{% if isBot %}<p class="warning">Bot: {{ botType }}</p>{% endif %}`,
Verdict: verdict,
Vars: map[string]string{"locale": "en-GB"},
})
if err == nil && rendered.Success {
fmt.Fprint(w, rendered.HTML)
}
Die Syntax der Vorlage ist identisch, ob Sie aufrufen RenderWidget von Go-,-Knoten oder verwenden <sb-widget> im Browser die gleiche Flüssige Engine die gleichen variablen Namen die gleiche Rendering-Pfad
Produktionsplan
graph LR
classDef input fill:none,stroke:#3b82f6,stroke-width:2px
classDef async fill:none,stroke:#a855f7,stroke-width:2px
classDef good fill:none,stroke:#22c55e,stroke-width:2px
classDef store fill:none,stroke:#f59e0b,stroke-width:2px
INT([Internet])
CF["Cloudflare<br/>Tunnel / CDN"]
CA["Caddy<br/>+ caddy-stylobot"]:::input
SD["StyloBot Sidecar<br/>:5090 gRPC · :5091 REST"]:::async
WEB["Upstream App<br/>Node / Go / ASP.NET"]:::good
DB[("SQLite<br/>sessions · reputation")]:::store
INT --> CF --> CA
CA -->|"gRPC Detect<br/>≤50ms"| SD
SD <-->|"persist"| DB
CA -->|"X-StyloBot-* headers"| WEB
WEB -->|"/_stylobot/partials/render<br/>(widget rendering)"| SD
Die vorgelagerte Anwendung ruft das Sidecar direkt für Widget-Rendering auf, um das Gateway zu umgehen... Widget Rendering benötigt den vollständigen Urteilskontext und passiert, nachdem die Anfrage bereits eine Gateway-Erkennung bestanden hat.
Fehler beim Öffnen auf jeder Ebene
Caddy plugin-,-Node Middleware - ,- und Go SDK alle ausfallen offen :-ein Sidecar-Timeout oder Fehler wird zu einem Warnprotokoll und eine permissive leere Urteil , nicht ein , 5 xx , die ,50-ms Caddy Deadline ist ein kalt - Start Sicherheitsmarge -;- die steady , --state Kosten auf einer warmen Verbindung ist , ist .
Der trade---off dieses codiert encodes-:-Blockierung legitimen Verkehr, weil die Erkennung nicht verfügbar ist schlimmer als fehlenden Bot-Verkehr während eines Sidecar-Ausfälles
Die Release-Serie geht weiter... mehr Beiträge auf Detektion Internals... ,... Bereitstellungsmuster...,... Beobachtbarkeit... und die kommerzielle Topologie sind noch nicht da.
- Verhalten nicht IdentitätWarum die Detektion verhaltensbedingt sein muss, ist nicht identitätsbezogen.
- Verhalten Bewusst WERDENVerwandeln Sie das Urteil in Razor-Steuerungspolitik
- Ungebundenes Wachstum in langen --Diensten finden und behebenDie Zuverlässigkeitsdisziplin, die den Motor unter anhaltendem Verkehr hält
- Verhalten--Bewusstsein TypScript UIDas gleiche Urteil tauchte in Express-,. Fastify und dem Browser auf.
- Die Sidecar-Architektur Dieser Artikel zeigt, wie der Motor über das Go SDK-, und das Caddy Plugin in jeden Stack steckt.
Quelle für die Implementierung github-.-com./-scottgal./-stylobotLive-Engine, Dashboard und kommerzielle Steuerungen am Stylobot-.-net.