zhxy/http服务器/appweb-4.3.4-0/doc/ref/appweb/ejsArchitecture.html

402 lines
28 KiB
HTML

<!-- BeginDsi "dsi/head.html" -->
<!DOCTYPE html>
<html lang="en">
<head>
<title>Embedthis Appweb 4.3.4 Documentation</title>
<meta name="keywords" content="embedded web server, web server software, embedded HTTP, application web server,
embedded server, small web server, HTTP server, library web server, library HTTP, HTTP library" />
<meta name="description" content="Embedthis Sofware provides commercial and open source embedded web servers for
devices and applications." />
<meta name="robots" content="index,follow" />
<link href="../../doc.css" rel="stylesheet" type="text/css" />
<link href="../../print.css" rel="stylesheet" type="text/css" media="print"/>
<!--[if IE]>
<link href="../../iehacks.css" rel="stylesheet" type="text/css" />
<![endif]-->
<link href="http://www.google.com/cse/style/look/default.css" type="text/css" rel="stylesheet" />
</head>
<body>
<div class="top">
<a class="logo" href="http://appwebserver.org/">&nbsp;</a>
<div class="topRight">
<div class="search">
<div id="cse-search-form"></div>
<div class="version">Embedthis Appweb 4.3.4</div>
</div>
</div>
<div class="crumbs">
<a href="../../index.html">Home</a>
<!-- EndDsi -->
&gt;<a href="index.html">Programmer Reference</a>&gt; Web Framework Architecture
</div>
</div>
<div class="content">
<div class="contentRight">
<h1>Quick Nav</h1>
<ul>
<li><a href="#webServerInterface">Web Server Interface</a></li>
<li><a href="#generator">Application Generator</a></li>
<li><a href="#parser">Web Page Parser</a></li>
<li><a href="#mvc">MVC</a></li>
<li><a href="#models">Models</a></li>
<li><a href="#views">Views</a></li>
<li><a href="#viewPipeline">View Pipeline</a></li>
<li><a href="#controllers">Controllers</a></li>
<li><a href="#routing">Routing</a></li>
<li><a href="#actions">Actions</a></li>
<li><a href="#deployment">Developing</a></li>
<li><a href="#deployment">Deployment</a></li>
</ul>
<h1>See Also</h1>
<ul>
<li><a href="architecture.html">Language Architecture</a></li>
<li><a href="../../api/native.html">Native APIs</a></li>
<li><a href="../../guide/appweb/programmers/index.html">Programmers Guide</a></li>
<li><a href="../../guide/appweb/users/index.html">User Guide</a></li>
</ul>
</div>
<div class="contentLeft">
<h1>Ejscript Web Framework Architecture</h1>
<p>The Ejscript Web Framework was designed to make it dramatically easier to create dynamic web
applications. The web framework provides an application generator, templating engine, a powerful
Model/View/Controller framework and a library of Ajax view controls to take the tedium out of creating web
applications. Via this framework, Ejscript drastically reduces the number of lines of code you need to
write for a compelling, dynamic web application.</p>
<p>This document describes the Ejscript Web Framework and how Ejscript is embedded in web servers to run
web applications and respond to web requests. It describes the flow of execution and the main processing
components.</p>
<h2>Ejscript Web Framework Architecture</h2>
<p>The Web Framework embeds the Ejscript language into leading web servers such as <a href=
"http://www.appwebserver.org">Appweb</a> and <a href="http://www.apache.org">Apache</a> to provide a
hosting environment for web applications. Ejscript learns from other web frameworks like Rails and PHP, to
deliver a web framework that uses JavaScript for server side web programming. The same language in the
client and server makes web programming that much easier.</p>
<p>The Web Framework builds upon the Ejscript core language and provides a web request handler, a
Model/View/Controller application framework and an edit-and-continue development model.</p><img src=
"../../images/ejsArchitecture.jpg" alt="Ejscript Web Framework Architecture" />
<p>The main components of the Ejscript Web Framework:</p>
<ul>
<li><a href="#webServerInterface">Web Server Interface</a> - Framework hosting and request handler</li>
<li><a href="#generator">Application Generator</a> - for applications, scaffolds and stubs</li>
<li><a href="#parser">Web Page Parser</a> - Parses web pages, applies view layouts and emits pure
JavaScript</li>
<li><a href="#mvc">Framework Classes</a> - MVC, Http Request and Ajax view classes</li>
<li>Ejscript compiler - Creates and caches application byte code</li>
<li>Ejscript Virtual Machine - executes the byte code and formats the response</li>
</ul><a id="webServerInterface"></a>
<h2 class="section">Web Server Interface</h2>
<p>The Ejscript Web Server Interface (or web interface) provides the interface and coupling between
Ejscript and the web server. It accepts incoming web requests from the web server, routes the request to
the appropriate application or ejscript web page, processes the output and passes it back to the web server
for transmission to the client.</p>
<h3>Hosting Alternatives</h3>
<p>Ejscript offers three possible hosting paradigms:</p>
<ul>
<li>CGI</li>
<li>FastCGI</li>
<li>Custom in-memory module</li>
</ul>
<p>The <a href="http://en.wikipedia.org/wiki/Common_Gateway_Interface">Common Gateway Interface</a> (CGI)
is a standard protocol for hosting applications in a web server. CGI offers good stability but low
performance.</p>
<p><a href="http://www.fastcgi.com/">FastCGI</a> is a replacement for CGI. It provides higher performance
than CGI by supporting multiple Http requests per FastCGI instance. It also offers improved stability by
isolating application instances.</p>
<p>Custom in-memory modules offer the highest performance. Ejscript provides modules for <a href=
"http://www.appwebserver.org/">Appweb</a> and <a href="http://www.apache.org/">Apache</a>. The custom
module, <b>mod_ejs</b>, provides excellent performance but less application isolation than FastCGI.</p>
<p>When using a custom in-memory module, each Ejscript application will typically define a URL alias using
the EjsAppAlias directive. For example:</p>
<pre>
EjsAppAlias /myAppName/ "/Directory/to/myApp"
</pre>
<p>This instructs the web server to send all requests with the URL prefix "myAppName" to Ejscript for
routing and processing.</p><a id="formData"></a>
<h3>Form Data</h3>
<p>The web interface converts incoming post and form data into a format suitable for easy processing by
Ejscript applications. Traditionally, form data is passed to web applications by environment variables. But
this format is often clumsy, doesn't scale and does not map well onto an object-oriented language such as
JavaScript.</p>
<p>Ejscript replaces environment variables with a params[] collection object and it transparently converts
form data into a nested collection of objects. It automatically converts dot separated form names into
objects that are addressable by dot notation.</p><a id="requestState"></a>
<h3>Request State</h3>
<p>The web interface will construct request, response and host objects that store request state. Ejscript
avoids the normal overhead in creating and populating these objects by using virtual, lazy construction.
Consequently, Ejscript applications incur minimal overhead when accessing request state.</p><a id="hosting"></a>
<h3>Interpreter Hosting</h3>A high performance web server must accept incoming requests, route to the
appropriate request handler, initialize the handler including necessary interpreters, gather response data,
transmit to the client and then tear down the handler. And this must be done many times per second, ideally
hundreds of times per second for dynamic content.
<p>To do this effectively, Ejscript pre-creates a master interpreter instance replete with all the
requisite system classes and web framework. When incoming requests arrive, the web interface quickly clones
this master interpreter to create a light-weight copy that is dedicated to the new request. The clone
leverages the system types and web framework in the master and so needs minimal initialization before it
can start servicing the web request.</p>
<p>Clone interpreters are not completely isolated. Controlled session state sharing is accomplished by
sharing session[] and application[] objects.</p>
<p><a id="generator"></a></p>
<h2 class="section">Application Generator</h2>
<p>The web framework supports two kinds of Ejscript web applications.</p>
<ul>
<li>Simple stand-alone web pages</li>
<li>Ejscript Model/View/Controller Applications</li>
</ul>
<p>Stand-alone web pages use embedded Ejscript code but do not use the full Model View Controller paradigm,
nor do they use the application generator. They typically use a "Post-Back" paradigm where form data is
posted back to the same page. The do not have controllers, models or view layouts.</p>
<p>MVC applications are more powerful. They have database models, controllers, views and layouts and
typically start life by using the application generator. This creates an application directory and
populates it with the necessary directories, configuration files and stubs to begin the application.</p>
<p>The application generator is a program named <b>ejsweb</b>. To create a new application called test:</p>
<pre>
ejsweb -v generate app test
</pre>
<p>This will create the following directories:</p>
<ul>
<li>test/config</li>
<li>test/controllers</li>
<li>test/db</li>
<li>test/models</li>
<li>test/src</li>
<li>test/views</li>
<li>test/views/layouts</li>
<li>test/web</li>
</ul>
<p>It will also create the following files:</p>
<ul>
<li>test/config/config.ecf</li>
<li>test/config/compiler.ecf</li>
<li>test/config/database.ecf</li>
<li>test/config/view.ecf</li>
<li>test/views/layouts/default.ejs</li>
<li>test/src/Test.es</li>
<li>test/controllers/Application.es</li>
<li>test/README</li>
</ul>
<p>The ejsweb program can also generate controllers. It is currently being enhanced to generate models,
views and entire scaffolds. To compile your application, use the ejsweb program:</p>
<pre>
ejsweb -v compile
</pre>
<p>During development time, the web framework uses <b>ejsweb</b> behind the scenes to transparently
recompile all or portions of the application if the developer modifies any model, view or
controller.</p><a id="mvc"></a>
<h2 class="section">Model, View, Controller Framework</h2>
<p>A Model View Controller framework, also known as MVC, is a proven paradigm for organizing web
applications. The model manages the state of the application including the database. The controller manages
the application, responding to inputs and invoking the relevant views to generate the user interface.</p>
<p>Originally developed in the '70s, it has been more recently adapted for web applications and been
popularized by frameworks such as <a href="http://www.rubyonrails.org">Ruby on Rails</a>. Ejscript uses the
same paradigm with a JavaScript and embedded spin.</p><a id="models"></a>
<h2 class="section">Models</h2>
<p>For object-oriented languages such as Ejscript, there is sometimes a mismatch between relational
database data and the JavaScript objects that are used to represent and manage that data. To solve this
problem, Ejscript provides an Object Relational Mapping (ORM) layer to make it easy to read, modify and
write database data. ORM layers map database tables to classes, rows to object instances and columns to
properties of the classes and objects. If a database has a table named Users, then there would be a model
class named User.</p>
<p>When Ejscript reads records from a database table it constructs an instance of the model class and
dynamically creates properties for each of the columns in the table. It also maps the SQL data types into
equivalent JavaScript types. This allows a natural access and update paradigm where the application can
deal with JavaScript objects while the ORM takes care of reading, querying and updating the database.</p>
<p>The web framework provides a powerful set of access methods to query, join, update and deal with SQL
tables. You can use higher level functions where the ORM generates appropriate SQL statements or you can
construct and issue your own SQL.</p>
<p>The ORM Methods include: belongsTo, find, findAll, findOneWhere, findWhere, getColumnNames,
getColumnTitles, getDb, getKeyNme, getNumRows, getTableName, hasAndBelongsToMany, hasMany, remove, save,
saveUpdate, setKeyName, setTableName, sql and trace.</p>
<p>The Ejscript ORM currently only provides one database connector for SQLite. It is expected that a future
release will add support for other major database engines.</p><a id="views"></a>
<h2 class="section">Views</h2>
<p>The View part of the Ejscript web framework is responsible for generating the user interface. It
typically takes an input HTML web page with embedded Ejscript and generates the HTML response to send back
to the client. However, views can also be generated by controllers and thus require no HTML page.</p>
<p>The Ejscript View framework provides:</p>
<ul>
<li>A templating engine for master layout pages</li>
<li>Embedded server-side JavasSript</li>
<li>A rich library of methods to render output</li>
<li>A consistent interface to Ajax libraries</li>
<li>A suite of view dynamic user controls such as table, chart, tab, tree, ...</li>
</ul><a id="viewPipeline"></a>
<h3>View Pipeline</h3>
<p>The View mechanism consists of a processing pipeline that progressively transforms the web page. Views
start with a partial HTML view page which typically contains embedded Ejscript. This is parsed by the Web
Page Parser and combined with layout views to create a composite web page. This is then parsed and
converted to pure Ejscript code which is compiled and cached in a module file (.mod). The module file can
be run repeatedly by the VM to generate the required HTML for the user view. <img src=
"../../images/ejsWebView.jpg" alt="View Pipeline" /></p>
<p>The time-intensive part of this pipeline processing occurs once, at development time. This is comprised
of the pipeline stages up to and including compilation. The often less costly run-time processing for each
request consists of reading the module file and executing it in the VM.</p><a id="parser"></a>
<h3>Web Page Parser</h3>
<p>The Web Page Parser is a templating engine and embedded script parser. It understands and processes
embedded javascript and layout directives to expand the view content pages and create a composite page that
represents an entire web page that the user will see.</p>
<p>A <b>templating engine</b> is an important part of a view framework. It allows you to specify the "look
and feel" and standard components of a web application in one place, and then reuse the "look and feel" in
content pages by simply referencing a layout page. The layout page typically contains the top level HTML
structure, style sheets and graphic content that is standard on every page. It also specifies the location
to insert content from content pages. The content pages focus on the content and data unique to that page
and they do not replicate the standard content specified in the master page. In this way, changing the
layout page in one place will automatically change every web page in the application.</p>
<p>The web page parser reads the content view pages that contain embedded ejscript code (with .ejs
extension). It blends the content page with the layout pages and converts it to a pure Ejscript program
(with .es extension) which represents the composite web page that the user will see.</p>
<p>Here is a simple layout page</p>
<pre>
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;@@title&lt;/title&gt;
&lt;link rel="stylesheet" type="text/css" href="@@style"/&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;img src="banner.jpg"&gt;
&lt;%@ content %&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>The <b>&lt;%@ content %&gt;</b> directive instructs the web page parser to insert the content page at
this location. The @@title and @@style directives access Ejscript variables set to the required content
title and style sheet at run-time.</p>
<p>Here is a simple content page:</p>
<pre>
&lt;h1&gt;Hello World&lt;/h1&gt;
&lt;p&gt;Today is &lt;%= new Date %&gt;
</pre>
<p>The web parser supports the following web page directives. These can be used in layout or content
pages.</p>
<ul>
<li>&lt;%= ejscript expression %&gt;</li>
<li>@@variable</li>
<li>&lt;% ejscript code %&gt;</li>
<li>&lt;% include "filename" %&gt;</li>
<li>&lt;%@ layout "file" %&gt;</li>
</ul>
<p>The &lt;%= ejscript expression %&gt; directive will evaluate the expression and substitute the resulting
expression value.</p>
<p>The @@variable directive is a shortcut for &lt;%= expression %&gt;.</p>
<p>The &lt;% ejscript code %&gt; directive will invoke the given code. No automatic substitution of output
occurs. However, the code can call "write()" to generate output in the place of the directive.</p>
<p>The &lt;% include "filename" %&gt; directive will include the given file name at the location of the
directive when parsing the web page. Include directives can be nested.</p>
<p>The &lt;%@ layout "file" %&gt; directive specifies the name of the layout page. By using this directive
in layout pages, you can build up the web page layout by nesting layout pages. If omitted in content pages,
which is usually the case, the default layout is views/layouts/default.ejs. If omitted in layout pages, it
is assumed the layout page is the top level layout page.</p>
<p>The web parser supports the following web page directive in layout pages:</p>
<ul>
<li>&lt;%@ content %&gt;</li>
</ul>
<p>This specifies the location for the content page data.</p>
<p><b>NOTE:</b> you do not have to use layout pages. Simple stand-alone web pages without layouts code are
supported. To disable templating, use a &lt;%@ layout="" %&gt; directive.</p>
<h3>View Controls</h3>
<p>The web framework provides a suite of view controls for common UI elements. These include button, chart,
checkbox, form, image, label, link, list, progress bar, radio button, table, tabs, text, textarea and tree.
The purpose of the controls is to be a themeable and skinnable set of UI controls that provides a higher
level of functionality than bare HTML. For example, the table control allows the easy display of database
data with sortable rows and selectable columns.</p>
<p>The view controls are implemented via View connector modules that communicate with the web framework's
View connector interface. This is a modular interface for industry Ajax and UI toolkits. The Ejscript web
framework provides a HTML view connector, and a Google Ajax Visualizer connector. Users can select which
connector module to use for a specific control on a control by control basis. Additional Ajax connector
libraries will be supported in the future.</p>
<p>The controls are bindable to data stored in models and many controls can dynamically refresh their
content using Ajax techniques without redisplaying the entire page.</p>
<p>Views can also use a library of view methods to generate and manage HTML output and responses. These
include: redirect, render, setCookie, setHeader, write, writeHtml and writeRaw.</p><a id="controllers"></a>
<h2 class="section">Controllers - Responding to Requests</h2>
<p>The role of the controllers is to manage the application and respond to inputs so controllers form the
heart of the web application. Controllers are typically bound to various URLs so that user input is routed
to specific actions within the controls. When a controller receives an incoming Http message, the requested
action is run. The action will typically mutate the state of the application in some manner and then render
a response view to the user.</p><a id="routing"></a>
<h3>Routing</h3>
<p>The Ejscript web framework routes incoming URL requests by tokenizing the request URL. The format used
is:</p>
<blockquote>
<p>http://site/APP/CONTROLLER/ACTION</p>
</blockquote>
<p>Where APP is the name of the application, CONTROLLER the name of the controller and ACTION is the name
of an action method within the controller. When such a URL request is received by Ejscript, it routes the
request to the specified controller and invokes the action method. The routing format is currently fixed
and not configurable but it is anticipated that user controlled routing will be added in a future
release.</p><a id="actions"></a>
<h3>Actions</h3>
<p>When a controller receives a request to service, it is dispatched to the action method specified in the
URL. The action is a simple function defined with an "action" namespace qualifier. The job of the action
method is:</p>
<ol>
<li>Respond to the request</li>
<li>Render a response view back to the client</li>
</ol>
<p>The action responds to the request by examining the request form parameters, query string and other Http
and application state information.</p>
<p>Here is a sample action method that updates a database table based on user submitted form data in
"params".</p>
<pre>
action function update() {
/* Update */
portfolio = Portfolio.find(params.id)
if (portfolio.saveUpdate(params.portfolio)) {
inform("Portfolio updated successfully.")
redirect("list")
}
}
</pre>
<p>An action method can explicitly render data by calling one of the render() methods. It can redirect the
client to a new URL via the redirect() method. Manual rendering is ideal for "RESTful" web services,
particularly when coupled with the XML/E4X capabilities of Ejscript.</p>
<p>If the action method does not explicitly render any data, the web framework will automatically render a
view page of the same name as the action method. That view has access to the controller and request
state.</p>
<p>Other methods used by Controller actions include: cache, createSession, destroySession, escapeHtml,
html, inform, keepAlive, makeUrl, render, renderFile, renderXml, reportError, setCookie, setHeader,
setHttpCode, setMimeType, warn and write.</p><a id="deployment"></a>
<h2 class="section">Development and Deployment</h2>
<p>There are two phases of use for Ejscript: Development and Deployment. When developing, developers need
quick turn-around with rapid test-modify-build cycles. Interpreted languages have a distinct advantage over
traditional compiled languages when used for such iterative or <a href=
"http://en.wikipedia.org/wiki/Agile_software_development">Agile Web Development</a>. Ejscript offers the
best of both. When developing, Ejscript runs as an interpreted environment. Changes made to web pages or
scripts cause the files to be parsed and compiled without restarting the web server. Simply reloading the
web pages in the browser will trigger the changed page to be rebuilt.</p>
<p>When ready for deployment, the entire application can be compiled into a single module file for easy
deployment.</p>
</div>
</div>
<!-- BeginDsi "dsi/bottom.html" -->
<div class="bottom">
<p class="footnote">
<a href="../../product/copyright.html" >&copy; Embedthis Software LLC, 2003-2013.
All rights reserved. Embedthis, Appweb, ESP, Ejscript and Embedthis GoAhead are trademarks of Embedthis Software LLC.</a>
</p>
</div>
<script src="http://www.google.com/jsapi" type="text/javascript"></script>
<script type="text/javascript">
google.load('search', '1', {language : 'en'});
google.setOnLoadCallback(function() {
var customSearchControl = new google.search.CustomSearchControl(
'000262706376373952077:1hs0lhenihk');
customSearchControl.setResultSetSize(google.search.Search.FILTERED_CSE_RESULTSET);
var options = new google.search.DrawOptions();
options.enableSearchboxOnly("http://appwebserver.org/search.html");
customSearchControl.draw('cse-search-form', options);
}, true);
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-179169-2']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</body>
</html>