在Genero FGL上也可以做出 RESTful 的 WEB Service。
先将回应WEB Request的方式拆解出来。如同之前在GAS设定章节中提到的,SERVICE与APPLICATION 的设定方式非常类似 (APPLICATION_LIST配置方式若不太清楚,可参考 [GAS] GBC上运作的Hello world!最下方的段落。)
整段 as.xcf 最下方就是配置 WEB SERVICE的 SERVICE_LIST段落。基底(parent) 基本都是 ws.default
若以 service 名称 svms配置服务可参考下列范例:
<APPLICATION Id="svms" Parent="ws.default" Abstract="TRUE">
<EXECUTION>
<PATH>$(res.zone)/svms/server</PATH>
<MODULE>SvmsServer.42r</MODULE>
<ACCESS_CONTROL>
<ALLOW_FROM>$(res.access.control)</ALLOW_FROM>
</ACCESS_CONTROL>
<POOL>
<START>0</START>
<MIN_AVAILABLE>1</MIN_AVAILABLE>
<MAX_AVAILABLE>1</MAX_AVAILABLE>
</POOL>
</EXECUTION>
</APPLICATION>
与APPLICATION段落有差别的地方,主要在多了POOL设定。此设定可编配初始在 GAS启动时,是否一并启动此服务(START),最大同时在系统中可并行 (MAX_AVALIABLE)支数,最小留存在系统中(MIN_AVALIABLE)支数。
最小留存只数的存在是为了不要让每次 REQUEST进来时,都要『等待』程序的启动(还要跑fglrun、连结database等等事务),应该要留下『待命用的』程序,随时随地等着 REQUEST做快速、即时的响应。
但是,要掂量掂量自己手上的 license。一个留存的service占用 1 runtime license。请仔细估算。别忘了还要保留给日常作业执行。
与 APPLICATION_LIST相同,在 SERVICE_LIST中也可以配置 GROUP
<GROUP Id="_default">$(res.zone.config)/xcf/gws-ws</GROUP>
<GROUP Id="demo">$(res.path.fgldir.demo.services)</GROUP>
<GROUP Id="svms">/u1/topprd4/svms</GROUP>
系统中也有预设提供的路径,我们也可以加上自己有的路径(svms)。这样的配置好处仍旧是:不用每次调整个别的程序时,都要做 fastcgidispatch/httpdispatch的重启。
在指定的路径下面(也就是上方标示的 /u1/topprd4/svms,若用RESOURCE_ID -$(res.xx)-替代,则需对应as.xcf最上方的讯息),则可以配置自己的应用程序名称,例如:我们配置一个名为『Vehicle.xcf』时,未来调用此服务的路径就会是『http://server_ip/wtopprd/svms/Vehicle 』开头 (此路径以下的拆解就会在程序内处理)。
下方的 server.4gl基本都可视为一个公版,主要在设定接收 WEB Service的设定。
IMPORT COM #取用httpd套件
IMPORT FGL ServiceVehicle #实际进行服务处理的子程序
SCHEMA svms
MAIN
DEFINE req com.HttpServiceRequest
#设定发生错误前作可以等待的时间(预设:5sec)
CALL com.WebServiceEngine.SetOption("readwritetimeout",60)
#设定客?端、HTTPRequest和TCPRequest等待与server建立连线的最长时间(预设30,-1为无限)
CALL com.WebServiceEngine.SetOption("connectiontimeout",25)
#设定REST 操作中的 MIME类型的支持。有XML/JSON(预设BOTH)
CALL com.webserviceEngine.SetOption("server_restdefaultformat","json")
# Start server
CALL com.WebServiceEngine.Start() #开始等待
WHILE TRUE
TRY
LET req = com.WebServiceEngine.GetHttpServiceRequest(-1)
IF req IS NULL THEN
IF int_flag THEN
EXIT WHILE
END IF
ELSE
CALL ProcessRequest(req) #服务进线,往子程序传递处理
LET int_flag = FALSE
END IF
CATCH
EXIT WHILE
END TRY
END WHILE
END MAIN
这一段主程序主用途相当的固定。接下来看主程序内的 function 对照服务路径的写法:
FUNCTION ProcessRequest(req)
DEFINE req com.HTTPServiceRequest
DEFINE path STRING
DEFINE ind INT
LET path = req.getUrlPath() #依照接续下来的路径区分要呼叫的子 function
#Request路径 /List
LET ind = path.getIndexOf("/List",1)
IF ind>0 THEN
LET path = path.subString(ind,path.getLength())
CALL ServiceVehicle.ProcessListRequest(req, path) #此处意思就是 /List就呼叫这个
# 42m模组名.function名
RETURN
END IF
#上述这一项,若 http://server_ip/wtopprd/svms/下除了List还有其他路径,
#均需要模仿此方式串接处理子程序
#其他不合路径一律列为未定义 Undefined request
CALL req.sendTextResponse(400,NULL,"The Function Still UNSupport!")
END FUNCTION
主程序段,主要在做路径对应处理的function,搭配提供的服务逐一配置即可。
子程序个别 function内,就是对应资料的处理。关於个别对应资料如何检核、校正调整,并写入database,就请参考相关章节进行编写。
IMPORT com
IMPORT util
IMPORT FGL Helper #FGL一些额外的套件
IMPORT FGL WSHelper #FGL一些处理WS的额外套件
SCHEMA svms
PUBLIC FUNCTION ProcessListRequest(req, path)
DEFINE req com.HTTPServiceRequest
DEFINE path STRING
CASE req.getMethod() #确认要接的RESTful型态
WHEN "GET" CALL GetListRequest(req,path) #GET方法的处理
WHEN "POST" CALL PostListRequest(req,path) #POST方法的处理
OTHERWISE
CALL req.sendTextResponse(400,NULL, "暂时不支持本服务")
END CASE
END FUNCTION
承接主程序的路径後,接下来在此子程序做的就是 ** action种类的判读**。从上述的范例可以看到,在这段作业中只接受 REST的GET与POST,而若是DELETE或其他动作传入,则会回传 400。
接下来以 GET的方法为例,说明处理方式:
PRIVATE FUNCTION GetListRequest(req,path)
DEFINE req com.HTTPServiceRequest
DEFINE path STRING
DEFINE ops Helper.OperationsType
DEFINE txt STRING
DEFINE token STRING
DEFINE now DATETIME YEAR TO SECOND
DEFINE query WSHelper.WSQueryType
CALL Helper.SplitOperations(path,"/List") RETURNING ops #确认List後面跟上的路径是否有次层
CALL req.getUrlQuery(query)
CASE ops.getLength()
WHEN 1 #Request发在本层的处理
#在这里写接收到资料的处理方式
LET response_string="xxxxx" #如果回传的是资料,记得转换为json格式的字串
#处理完成後要回传的字串
CALL req.setResponseHeader("Content-Type","application/json") #回传格式设为json
CALL req.setResponseHeader("Cache","no-cache") #不支持cache
CALL req.sendTextResponse(200,NULL, response_string) #处理完成後,回传200及对应讯息
WHEN 2 #如果有两层的 Request路径,例如 /List/OnlyThisWeek 只找本周来的资料
# 处理 /Commmant/Asktime
IF ops[1]=="OnlyThisWeek" AND query.getLength()==1 THEN
#放处理机制,回传资料放入 response_this_week
CALL req.sendTextResponse(200, NULL, response_this_week)
END IF
OTHERWISE CALL req.sendTextResponse(400,NULL,"暂时不提供此路径的服务")
END CASE
END FUNCTION
透过上述程序的组装,我们就可以完成基本的 RESTful 程序搭建。
从事网路维运工作已超过15个年头,曾在公司内部担任资料中心网路管理员,并偕同Intranet网域网路...
0. 进度条 模型 进度 VGG Net (完成) ResNet (完成) DensNet (此篇)...
此篇作为 Bootstrap 5 客制化 sass 的序章,会大致讲解什麽是 Sass 以及优势。...
HTTP 与Web 请求 HTTP,超文本传输协定(HyperText Transfer Proto...
大家好我是 Gui,一名刚於私立科大资管系毕业的社会新鲜人,这是我第一次参与 IT 铁人赛,既紧张又...