Web
Overview
The web pod defines the standard APIs used to handle both client and server side HTTP requests.
Client side HTTP requests:
WebClient
: manages client side of the HTTP protocol
Server side web APIs are organized into the primary classes:
Weblet
: an entity which processes a web request - it is very much like a Java servlet.WebReq
: models an incoming web request such as the method, uri, request headers, and input stream.WebRes
: models the outgoing web response such as the status code, response headers, and output stream.WebService
: base class for the HTTP server implementations and used to configure the web pipeline.
WebClient
The WebClient
class is used to manage client side HTTP requests and responses. The basic lifecycle of WebClient:
- configure request fields such as
reqUri
,reqMethod
, andreqHeaders
- send request headers via
writeReq
- optionally write request body via
reqOut
- read response status and headers via
readRes
- process response fields such as
resCode
andresHeaders
- optionally read response body via
resIn
Using the low level methods writeReq
and readRes
enables HTTP pipelining (multiple requests and responses on the same TCP socket connection). There are also a series of convenience methods which make common cases easier.
See docCookbook::Web for example code.
Weblets
Pretty much anything that touches a HTTP request should be a subclass of web::Weblet
. The lifecycle of a Weblet is quite simple:
- all web requests are guaranteed to be called on their own thread with the thread locals "web.req" and "web.res"
make
: the constructor automatically initializes thereq
andres
fields with the current thread'sWebReq
andWebRes
- so there no need to pass the request and response aroundservice
: theservice
method can be overridden directly to handle the request, or the default implementation will route to thedoGet
,doPost
, etc methods
WebReq
The web::WebReq
class models the request side of a HTTP request. Common methods you will use include:
method
: HTTP method such as "GET" or "POST"uri
: the request URI parsed into asys::Uri
which allows you access the parsed path and query segments.headers
: a case insensitiveStr:Str
map of the request HTTP headersin
: access to the raw input stream of the requestform
: access to the parsed form datacookies
: aStr:Str
map of cookiessession
: aStr:Obj
map used to stash stuff for the browser "connection" between HTTP requestsstash
: aStr:Obj
map used to stash stuff only for the life of requestresource
: the webapp resourceuserAgent
: access the parsed "User-Agent" header
WebRes
The web::WebRes
class models the response side of a HTTP request. A WebRes
has the following lifecycle:
- Uncommitted: at this point nothing has been written back on the TCP socket and
statusCode
,headers
, andcookies
are still configurable - Committed: at this point the HTTP response headers have been written, and you can write the response content via the out stream. Once a response is committed, attempts to access
statusCode
,headers
,cookies
,redirect
, orsendError
will raise an exception - Done: at this point the response is complete - for example once the
redirect
orsendError
method is called, the response is done
Common methods you will use include:
statusCode
: sets the HTTP status code - must be set before commitheaders
: aStr:Str
map of HTTP headers - must be set before commitcookies
: used to set the cookie header - must be set before commitout
: the output stream for writing the content - first call commits the responseisCommitted
: check commit stateisDone
: check done statesendError
: used to send an error status coderedirect
: used to send a redirect status code
WebRes is a fairly low level API which requires the commit state model to avoid buffering the content. The Widget API provides a higher level model which buffers the response to provide more flexibility.
WebSessions
The web::WebSession
class models the client session which allows you to persist state between HTTP requests. WebSessions in Fan are cookie based using the cookie name "fanws". The default session implementation stores sessions in memory for up to one hour, then clears them from the cache - session state is not persisted between VM restarts.
WebSession provides a Str:Obj
map to store arbitrary name/value pairs. You can use the map
, get
, or set
methods to manage session state. You can use delete
to explicitly delete the session cookie and server side state. The values stored in a WebSession should always be serializable objects.
WebSessions are created and accessed via the WebReq.session
method. The first time a session is accessed it sets the cookie header in the response - therefore sessions should always be accessed before the response is committed. Deleting a session also requires setting the cookie header and must done before the response is committed.
Example of storing a counter in a session:
override Void doGet() { Int count := req.session.get("counter", 0) req.session["counter"] = count + 1 res.headers["Content-Type"] = "text/plain" res.statusCode = 200 res.out.printLine("session counter=$count") }
WebServices
The web::WebService
class is the base class for plugging in web server implementations. Fan comes bundled with the wisp::WispService
which implements a web server purely in Fan code - so you can use it without the fuss of setting up additional software. The plan is over time to add implementations for plugging into a Java Servlet container, into IIS, and to have a fan_mod for Apache. Most important is that all Fan code written to the web pod APIs should be insulated from the web server implementation.
WebStep Pipeline
The WebService.pipeline
field defines how web requests are processed using a pipeline of WebSteps
. WebSteps are just like Weblets, but are const so that they can be configured on the const WebService. The web pod itself is a low layer API and doesn't define any WebSteps itself. The webapp pod is layered above the web pod and defines a whole mini-framework of steps you can use.