xlang webserver 用法详解
未分类2025-03-23 17:51:54概述:
在 xlang 的 webserver 开发中,具有以下和 javaWeb 类似的三大组件
- HttpServer Http服务器容器主类
- Website 站点主类
- HttpServlet 用于处理Http 和 Websocket 请求的接口
一. HttpServer
HttpServer 类负责整个服务器的运行,类声明如下:
class HttpServer{
public static const int DEFAULT_MODEL;
public static const int SELECT_MODEL;
public static const int POLL_MODEL;
public static const int EPOLL_MODEL;
public static const int ALLOW_UPGRADE;
public HttpServer();
public bool setMaxConnection(int max);
public bool setConnectionTimeout(int millisec);
public bool setIpConnectionLimit(int limit);
public bool setThreadPoolSize(int size);
public int addWebsite(String domain, Website website);
public void quiesce();
public void close();
public bool stop();
public bool isRunning();
public bool start(int flags, int port);
public bool configHttps(bool enable, String certContent, String keyContent);
};
| 名称 | 类型 | 说明 |
| DEFAULT_MODEL | 常量 | 指示以默认的模式运行(不同平台默认可能不同,一般是 select 模式) |
| SELECT_MODEL | 常量 | 指示服务器以 select 模式运行 |
| POLL_MODEL | 常量 | 指示服务器以 poll 模式运行(linux) |
| EPOLL_MODEL | 常量 | 指示服务器以 epoll 模式运行(linux) |
| ALLOW_UPGRADE | 常量 | 启用websocket, 指示服务器可以将 http 连接升级为 websocket连接 |
| HttpServer() | 构造方法 | 创建一个 HttpServer 实例 |
| bool setMaxConnection(int max) | 方法 | 限制最大连接数为max |
| boolsetConnectionTimeout(int millisec) | 方法 | 连接超时时间(客户端连接后超过时间未传输数据将被断开) |
| boolsetIpConnectionLimit(int limit) | 方法 | 限制单IP的最大并发连接数 |
| boolsetThreadPoolSize(int size) | 方法 | 设置工作线程数量 |
| int addWebsite(String domain, Website website) | 方法 | 向服务器容器中添加站点, |
| void quiesce() | 方法 | 允许现有连接继续,但不再接受新 |
| bool stop() | 方法 | 停止服务 |
| void close() | 方法 | 关闭服务器,并清理资源 |
| bool isRunning() | 方法 | 返回值指示服务器是否在运行中 |
| bool start(int flags, int port) | 方法 | 在端口 port 上启动服务器, flags 参数为表中常量 |
| bool configHttps(bool enable, String certContent, String keyContent) | 方法 | 已弃用,不再生效 |
二. Website
Website 负责站点业务,类声明如下:
class Website{
public Website();
public bool registryServlet(HttpServlet servlet);
public void setRootDirectory(String path);
public String getRootDirectory();
public String getTempDirectory();
public void setEnabled(bool on);
public void setTempDirectory(String path);
public void configCacher(bool on, int singlemax, long totalmax);
public void configSession(int sessionMax, int timeout);
public void clearCacher();
public void clearSession();
public bool setHeader(String pattern, String key, String value);
public bool setFooter(String pattern, String key, String value);
public bool addDefaultPage(String indexname);
public bool addMimeType(String pattern, String key);
public String mapServerPath(String local, String host);
public String mapLocalPath(String url, String host);
public bool removeCache(String localpath);
};
| 名称 | 类型 | 说明 |
| Website | 方法 | 创建 WebSite 实例 |
| registryServlet | 方法 | 注册 Servlet |
| setRootDirectory | 方法 | 设置网站根目录 |
| getRootDirectory | 方法 | 获取网站根目录 |
| getTempDirectory | 方法 | 获取临时目录 |
| setEnabled(bool on) | 方法 | 启用或禁用网站 |
| setTempDirectory(String path) | 方法 | 设置临时目录 |
| configCacher(bool on, int singlemax, long totalmax) | 方法 | 设置缓存,主要指静态文件缓存,on 指示启用或禁用,singlemax 指适用缓存的单个文件最大上限,totalmax是总的缓存最大上限 |
| configSession(int sessionMax, int timeout) | 方法 | 设置session的最大数量和超时限制(毫秒) |
| clearCacher() | 方法 | 清理静态文件缓存 |
| clearSession() | 方法 | 清理所有session |
| setHeader(String pattern, String key, String value) | 方法 | 设置对匹配 pattern 规则的 uri 响应中添加 Header |
| setFooter(String pattern, String key, String value) | 方法 | 设置对匹配 pattern 规则的uri 响应中添加 Footer |
| bool addDefaultPage(String indexname) | 方法 | 指定索引页 |
| addMimeType(String ext, String key) | 方法 | 设置指定扩展名的mimetype |
| String mapServerPath(String local, String host) | 方法 | 将服务器上的本地路径转换为网站路径 |
| String mapLocalPath(String url, String host) | 方法 | 将网站路径转换为服务器上的本地路径 |
| removeCache(String localpath) | 方法 | 移除指定静态文件缓存 |
三. HttpServlet
HttpServlet 负责处理指定 uri 的业务, 接口声明如下
class HttpServlet{
static const int FLAG_POSTSTREAM;
static const int FLAG_LOGERROR;
static const int FLAG_SERVLET;
static const int FLAG_WEBSOCKETLET;
HttpServlet(int flags, String pattern);
HttpServlet(int httpcode);
void doGet(HttpServletRequest request, HttpServletResponse resp);
void doPost(HttpServletRequest request, HttpServletResponse resp);
void onOpen(WebSocketSession session);
void onClose(WebSocketSession session, String reason);
void onError(WebSocketSession session);
void onMessage(WebSocketSession session, String message);
void onBinary(WebSocketSession session, byte [] message);
};
常量说明:
- FLAG_POSTSTREAM
- 指示该 uri 的 post 数据流操作全部由手动接管
- 注意: 设置此 flags 后,post的 form 以及 multipart 数据将不会自动解析,需要手动编码处理。
- FLAG_LOGERROR
- 指示将异常信息打印到页面
- FLAG_SERVLET
- 指示该接口响应 http 请求
- FLAG_WEBSOCKETLET
- 指示该请求响应 websocket 请求
构造:
- HttpServlet(int flags, String pattern);
- 创建实例, flags 使用上面常量组合, pattern 指示处理哪些 uri 请求,该参数为正则表达式, 所有能被此表达式匹配的 uri 均交由此接口处理。
- HttpServlet(int httpcode);
- 创建实例, 参数指示了在发生 Http 哪种错误(代码)时,将交由此接口进行处理,比如 404。
Http 请求处理:
- void doGet(HttpServletRequest request, HttpServletResponse resp);
- 响应 get 请求
- void doPost(HttpServletRequest request, HttpServletResponse resp);
- 响应 post请求
WebSocket 请求处理:
- void onOpen(WebSocketSession session);
- 响应 WebSocket 的连接事件
- void onClose(WebSocketSession session, String reason);
- 响应 Websoket 关闭事件
- void onError(WebSocketSession session);
- 响应 WebSocket 错误事件
- void onMessage(WebSocketSession session, String message);
- 响应 WebSocket 文本消息事件
- void onBinary(WebSocketSession session, byte [] message);
- 响应 WebSocket 数据流事件
*注意事项
- 构造参数中 若 flags 为 0 时, 默认为 FLAG_SERVLET。
- 当未使用 FLAG_POSTSTREAM 标志时, 接口将自动处理 Content-Type 为 form 和 multipart 的数据,并将结果存入 request 中,使用 getParam() 进行提取,而Content-Type 为此两种以外的类型时,则不会处理,需要通过接口上对应方法的HttpServletRequest参数的成员方法 readPostData 进行读取。
- 当使用了 FLAG_POSTSTREAM 标志, 该接口上的所有 post 数据将不会被自动处理, 需要通过接口上对应方法的HttpServletRequest参数的成员方法 readPostData 进行读取并手动处理。
- 当使用了 FLAG_POSTSTREAM 标志时,用户需要自行编写处理逻辑, 也可以使用HttpServletRequest 类提供的处理 post 数据的内置方法(仅用于解析 Content-Type 为 form 和 multipart 的数据流), 用法如下:
- 对应要处理的 HttpServletRequest request 需要通过 setOnParseListener 设置解析回调:
-
_request.setOnParseListener(new RequestParseListener(){ void onItemParsed(String key, String filename, String contentType, String transferEncoding, byte [] data, long dateInOffset)override{ // todo 添加解析结果 } }); - 然后通过循环读取post流并调用解析方法,解析结果将会通过上述回调函数送达:
-
byte [] data = new byte [1024]; int readed = 0; while (0 < (readed = _request.readPostData(data, 0, data.length))){ _request.parsePostedData(data, 0, readed); }
HttpServletRequest 类
class HttpServletRequest{
public InetAddress getClientAddress();
public String getHeader(String name);
public String getCookie(String key);
public Object getSession(String key);
public void setSession(String key, Object value);
public String getParam(String key);
public ServletRequestItem [] getParameter(String key);
public String [] getParams(String key);
public String [] getParamKeys();
public String getArg(String key);
public String [] getArgs(String key);
public String [] getArgKeys();
public String [] getLocalFilepath(String key);
public String [] getFileName(String key);
public Website getWebsite();
public String getUrl();
public String getHost();
public String getMethod();
public void setUserData(Object data);
public Object getUserData();
public String getServerName();
public int getServerPort();
public String getQueryString();
public String getScheme();
public int readPostData(byte [] data, int offset, int len);
public bool setOnParseListener(RequestParseListener listener);
public bool parsePostedData(byte [] data, int offset, int length);
};
| 名称 | 说明 |
| InetAddress getClientAddress() | 获取客户端地址 |
| String getHeader(String name) | 获取请求头参数 |
| String getCookie(String key) | 获取 cookie |
| Object getSession(String key) | 获取session对象 |
| void setSession(String key, Object value) | 设置session对象 |
| String getParam(String key) | 获取 post 数据中的参数值 |
| ServletRequestItem [] getParameter(String key) | 获取 post 数据中的参数对象 |
| String [] getParams(String key) | 获取 post 数据中的参数,可获取多个参数 |
| String [] getParamKeys() | 获取 post 数据中所有的参数 key |
| String getArg(String key) | 获取 url 中的参数值 |
| String [] getArgs(String key) | 获取 url 数据中的参数,可获取多个参数 |
| String [] getArgKeys() | 获取 url 数据中所有的参数 key |
| String [] getLocalFilepath(String key) | 获取 post 数据中上传的文件路径 |
| String [] getFileName(String key) | 获取 post 数据中上传的文件名 |
| Website getWebsite() | 获取 Website 对象 |
| String getUrl() | 获取参数 url |
| String getHost() | 获取 host 名称 |
| String getMethod(); | 获取请求方法 |
| void setUserData(Object data); | 设置用户数据, 与HttpServletRequest 对象生命周期绑定 |
| Object getUserData() | 获取设置的用户数据 |
| String getServerName() | 同 getHost |
| int getServerPort() | 获取服务器端口 |
| String getQueryString() | 获取url参数字符串 |
| String getScheme() | 获取协议标识, * 注意:此方法可能获取不正确, 建议配合 nginx 前端获取 nginx 的转发头部字段。 |
| int readPostData(byte [] data, int offset, int len) | 读取post数据流 |
| bool setOnParseListener(RequestParseListener listener) | 设置 post 数据流解析结果回调 |
| bool parsePostedData(byte [] data, int offset, int length); | 解析 post 数据流, * 注意:请阅读上一节中的注意事项 |
HttpServletResponse 类
class HttpServletResponse{
public void print(String text);
public void write(byte [] buffer, int pos, int length);
public void setOutputStream(Stream stream);
public void setResponseCode(int code);
public void setCookie(String key, String value);
public void addHeader(String key, String value);
public void setHeader(String key, String value);
public void setContentType(String sType);
};
| 名称 | 说明 |
| void print(String text) | 输出字符串 |
| void write(byte [] buffer, int pos, int length) | 向响应流写入数据 |
| void setOutputStream(Stream stream) | 向响应流插入数据流 |
| void setResponseCode(int code) | 设置 HTTP 响应代码 |
| void setCookie(String key, String value) | 设置 cookie 数据 |
| void addHeader(String key, String value) | 添加响应头 |
| void setHeader(String key, String value) | 设置响应头, * 注意:将删除key对应的旧响应头数据 |
| void setContentType(String sType) | 设置ContentType |
*注意事项
print, write, setOutputStream 均为输出响应数据,使用 print 和 write 输出的数据流会被短暂的缓存在内存中,待doGet 或者doPost 方法执行完毕后才会发送给客户端,而setOutputStream 设置的输出流则会在doGet 或者doPost方法调用结束后被回调读取流并即时发送给客户端,因此,数据量较少时使用 print, write,数据量较大时应使用 setOutputStream ,以免内存占用过高导致问题。
当 print, write, setOutputStream 均有数据输出时,优先发送 print, write (按照两者调用顺序) 写入的数据,后处理 setOutputStream 的数据流.
Xlang Script Page
xlang 动态页面,是为了兼容旧的动态页面技术,在 xsp 文件中 使用 <% %> 包裹起来的块为 xlang 代码,会被编译器进行编译。
使用 <xsp:include page="other.xsp" /> 包含的其他页面会在编译时被插入此代码的位置并进行编译。
使用 <%@PageFlags = FLAGS %> 改变页面默认行为,FLAGS 为HttpServlet 中的常量 FLAGS ,如将错误信息打印到页面,则使用 <%@ PageFlags = FLAG_SERVLET | FLAG_LOGERROR %> , 若不使用代码指定,则默认只有 FLAG_SERVLET 。
xsp 中的可用变量为 session 或者 request (两者等价,同为 HttpServletRequest 类型),用于处理请求,response 或者 out (两者等价,同为 HttpServletResponse 类型)用于处理响应, WebSocket 请求在 xsp 页面中不可被处理,只能通过 Servlet 响应。
示例代码
//xlang
package System{
public class out{
public static int println(String text){
return _system_.consoleWrite(text + "\n");
}
public static int print(String text){
return _system_.consoleWrite(text);
}
};
};
using { System; };
class XServlet : HttpServlet{
public XServlet(){
/**
@super 调用基类构造
@XServlet.FLAG_LOGERROR 将错误打印到页面,
@url "/action/*" 正则表达式, 匹配的url请求将被此servlet接管.
*/
super(XServlet.FLAG_LOGERROR, "/api/*");
}
void doGet(HttpServletRequest request, HttpServletResponse response)override{
//获取参数
String [] args = request.getArgs("name");
response.print("<html><head><meta charset=\"utf-8\" /></head><body>");
if (args != nilptr){
// 设置跨域
/*response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Headers", "X-Requested-With,Content-Type,Accept");
response.addHeader("Access-Control-Allow-Methods", "HEAD,GET,POST,PUT,DELETE,OPTIONS");*/
response.print("<b style=\"font-size:40px;\">Hello " + args[0] + "!</b>");
response.print(" <br/>Welcome to xlang Webserver");
}else{
response.print("<b style=\"font-size:40px;\">Welcome to xlang Webserver!</b>");
}
response.print("</body></html>");
}
void doPost(HttpServletRequest request, HttpServletResponse response)override{
doGet(request, response);
}
};
int main(String [] args){
/** #################################################################################*/
/** 创建web站点*/
Website wb = new Website();
/** 设置站点的静态文件目录为工作目录下的wwwroot文件夹*/
wb.setRootDirectory(_system_.getWorkDirector().appendPath("wwwroot"));
/** 设置站点的临时目录为temp, 用于网站缓存上传的数据流
注意:处理了onPostStream的servlet中不会保存临时文件,将回调onPostStream
*/
wb.setTempDirectory("temp");
/** 开启设置静态文件缓存, 单个文件大小上限为1M, 整个网站缓存上限为100M*/
wb.configCacher(true,1024*1024,100*1024*1024);
/** 注册一个servlet处理动态事务*/
wb.registryServlet(new XServlet());
/** 设置站点的默认首页, 多个用分号分割*/
wb.addDefaultPage("index.html");
/** #################################################################################*/
/** 创建http服务器*/
HttpServer server = new HttpServer();
/** 设置服务器的线程池大小为 4个*/
server.setThreadPoolSize(4);
/** 将站点添加到服务器中,参数1为IP或者域名,多个用分号分割*/
server.addWebsite("*;127.0.0.1;localhost", wb);
/** 开启服务器, 模式为默认模式,可选为POLL EPOLL SELECT, 端口8889*/
if (server.start(HttpServer.DEFAULT_MODEL,8889)){
/** #################################################################################*/
System.out.println("start server success!\nopen URL with Webbrowser:\nhttp://localhost:8889/\nhttp://localhost:8889/api/?name=xlanguser\nhttp://localhost:8889/api/");
Thread.sleep(-1);
}else{
/** #################################################################################*/
System.out.println("start server filed! please check port(8889) occupancy!");
Thread.sleep(3000);
}
return 0;
}
上一篇:tomcat 服务器问题排查及优化下一篇:xlang加解密算法支持说明

