JWSGI接口
注解
JWSGI并不是一个标准,然而,如果你喜欢JWSGI,那么何不发送一个RFC给uWSGI邮件列表。我们对标准没有特别的兴趣,但是谁知道呢……
JWSGI是考虑Java的WSGI/PSGI/Rack方式的一个口子。
如果,由于某种模糊的原因,你想要用JVM语言开发应用,并且你不想要部署一个巨大的servlet栈,那么JWSGI应该与你同行。
它是一个非常简单的协议:调用一个公共方法,它接收一个 HashMap
作为它唯一的参数。这个HashMap包含了CGI风格的变量,而 jwsgi.input
包含了一个Java InputStream对象。
这个函数必须返回一个包含3个对象的数字:
status
(java.lang.Integer) (例如:200)headers
(HashMap) (例如:{“Content-type”: “text/html”, “Server”:“uWSGI”, “Foo”: [“one”,”two”]})body
(可能是一个String,一个String数组,一个File或者一个InputStream对象)
例子
一个简单的JWSGI应用看起来像这样:
- import java.util.*;
- public class MyApp {
- public static Object[] application(HashMap env) {
- int status = 200;
- HashMap<String,Object> headers = new HashMap<String,Object>();
- headers.put("Content-type", "text/html");
- // a response header can have multiple values
- String[] servers = {"uWSGI", "Unbit"};
- headers.put("Server", servers);
- String body = "<h1>Hello World</h1>" + env.get("REQUEST_URI");
- Object[] response = { status, headers, body };
- return response;
- }
- }
如何使用它?
你同时需要’jvm’插件和’jwsgi’插件。项目中有一个名为’jwsgi’的构建配置文件可以用,允许你实现带jvm+jwsgi的单片构建:
- UWSGI_PROFILE=jwsgi make
- 用
javac
编译你的类。
- javac MyApp.java
- 运行uWSGI,并且指定要运行的方法 (使用格式class:method)
- ./uwsgi --socket /tmp/uwsgi.socket --plugins jvm,jwsgi --jwsgi
- MyApp:application --threads 40
这将会在UNIX socket /tmp/uwsgi.socket上运行一个JWSGI应用,使用40个线程。
读取请求体
jwsgi.input
项是一个 uwsgi.RequestBody
对象 (java/io/InputStream的子类). 通过它来访问请求体。
- import java.util.*;
- public class MyApp {
- public static Object[] application(HashMap env) {
- int status = 200;
- HashMap<String,Object> headers = new HashMap<String,Object>();
- headers.put("Content-type", "text/plain");
- int body_len = Integer.parseInt((String) env.get("CONTENT_LENGTH"));
- byte[] chunk = new byte[body_len];
- uwsgi.RequestBody input = (uwsgi.RequestBody) env.get("jwsgi.input");
- int len = input.read(chunk);
- System.out.println("read " + len + " bytes");
- String body = new String(chunk, 0, len);
- Object[] response = { status, headers, body };
- return response;
- }
- }
注意用 read(byte[])
来代替传统的 read()
。后者低效地每次读取一个字节,而前者一次读取一个更大的块。
JWSGI和Groovy
因为它是低级别的,因此,JWSGI标准可以原样用于JVM上运行的其他语言。例如,这是一个”Hello World” Groovy样例:
- static def Object[] application(java.util.HashMap env) {
- def headers = ["Content-Type":"text/html", "Server":"uWSGI"]
- return [200, headers, "<h1>Hello World</h1"]
- }
一个提供静态文件服务的例子:
- static def Object[] application(java.util.HashMap env) {
- def headers = ["Content-Type":"text/plain", "Server":"uWSGI"]
- return [200, headers, new File("/etc/services")]
- }
第二个方法非常有效,因为它将滥用uWSGI内部功能。例如,如果你启用了卸载,那么你的worker线程将会被突然释放。要加载Groovy代码,记得编译它:
- groovyc Foobar.groovy
然后运行它:
- ./uwsgi --socket /tmp/uwsgi.socket --plugins jvm,jwsgi --jwsgi Foobar:application --threads 40
JWSGI和Scala
就像Groovy,你可以用Scala编写JWSGI应用。你只需要入口点函数来使用原生的Java对象:
- object HelloWorld {
- def application(env:java.util.HashMap[String, Object]): Array[Object] = {
- var headers = new java.util.HashMap[String, Object]()
- headers.put("Content-Type", "text/html")
- headers.put("Server", "uWSGI")
- return Array(200:java.lang.Integer, headers , "Hello World")
- }
- }
或者一种更Scala的方式:
- object HelloWorld {
- def application(env:java.util.HashMap[String, Object]): Array[Object] = {
- val headers = new java.util.HashMap[String, Object]() {
- put("Content-Type", "text/html")
- put("Server", Array("uWSGI", "Unbit"))
- }
- return Array(200:java.lang.Integer, headers , "Hello World")
- }
- }
一旦用 scalac <filename>
编译好了,你可以像这样运行:
- ./uwsgi --socket /tmp/uwsgi.socket --plugins jvm,jwsgi --jwsgi HelloWorld:application --threads 40