大道至简,新一代企业应用无栈开发

平台之上,一种语言,可视化、脚本化、全端一体化开发

站点运行环境

直接在站点服务上运行,可以访问整个站点的所有内容

docutils document without title

1   通过Web访问

1.1   浏览器地址栏直接访问

这种方法,在前端教程已经讲过。在浏览器中访问方法为:

http://<站点域名:端口>/对象地址/@<应用名>:<脚本名>
  • 脚本内可以使用context、request、view等变量(具体解释见后)
  • 会检查是否有权限调用

输出结果会组装到系统的皮肤模板:

  • 如果返回字符串,直接填充到了main区域

  • 也可以返回一个dict,填充模板各个区域:

    {'main': '',  # 主正文区域
     'left': '',  # 左侧区域,通常是导航栏
     'right': '',  # 右侧区域,通常是附加辅助信息
     'side': '', # 侧边悬浮区,用于反馈问题、网站编辑工具,回到顶部等按钮
     'title': '',  # 页面标题
     'description': '' # 页面描述信息}
    

上面dict中的每个值,可以是包含html内容的字符串,也可以是ui组件(如: (ui.h1('我们'))。

地址中的参数,会直接传递到脚本中的对应参数,比如:

http://path/to/script?aa=1&bb=2

也可以支持参数后缀(:int, :float, :boolean, :list 等),来定义参数类型,平台自动会做类型转换,比如:

http://path/to/script?aa:int=1&bb:float=2

传递的参数可在request中获取:

  1. request['aa'] 里面直接就是对应的数据类型(整数、布尔、列表等),不需要在转换
  2. 如果脚本包含了同名的参数,比如 aa, bb ,会直接赋值到参数,不需要从request中获取

(注:如果看到含有 @@ 的地址,这些属于平台底层的内置脚本,不属于软件包)

1.2   通过RESTful API来调用

所有脚本都可以直接通过RESTful API进行调用,地址为:

/api/v3/x-api/<应用名>:<脚本名>

也可以直接通过edo_client的 xapi 方法来调用,比如:

wo_client = root.get_client(request, 'workonline', site_name)
result = wo_client.xapi('xxx.xxx:xxx', aa=1, bb=2)

详细参看: https://dev.easydo.cn/++intid++503576345/@view.html

1.3   前端组件Ajax请求

平台提供的前端ui组件,触发事件之后,可以直接直接调用python脚本。

比如:

#点击链接
ui.link('something').on('click', context, request, 'xxx.xxx:xxxx')

# 点击按钮
ui.button('submit').on('click', context, request, 'xxx.xxx:xxxx')

# 输入变化
ui.input_text('name').on('change', context, request, 'xxx.xx:xxx')

# 表单提交::
ui.form().on('submit', context, request, 'xxx.xxx:xxxx')

还可以直接传递参数到脚本,并保持数据类型,比如:

link.on('click', 'xxx.xxx:xx', context, request,
    aa=1, bb=True,
    cc=['aa', 1], dd=[1, 2, True],
    ee={'a':1, 'b':True, 'c':'hello'})

和浏览器直接访问一样:

  • 脚本内可以使用context、request、view等变量(具体解释见后)
  • 会检查是否有权限调用

2   作为函数调用

脚本可在其他脚本或者表达式中调用。

2.1   同步调用

作为一个函数,可以被其他脚本调用:

result = root.call_script('zopen.xxx:ass', aaa=233, bbb=123)

在脚本中调用脚本,可直接使用传入的参数,另外还可以访问 root 变量。 和浏览器调用不同:

  1. 不能直接context, request,view等变量,不能直接使用,需要额外传入:

    root.call_script('zopen.xxx:xxx', context=context, request=request, view=view)
    
  2. 脚本的渲染模板不再起作用

  3. 脚本的权限也不再起作用

2.2   异步调用

对于耗时比较长的工作(如发送邮件、文件格式转换、文件上传、下载),可以异步调用脚本,在后台队列中运行:

root.call_script_async('zopen.xxx:ass', aaa=233, bbb=123)

注意:

  1. 异步调用对参数类型有要求, 只能传递可以json序列化的简单参数

    因此不能传递对象,如果是内容对象,需要先转换成uid等之后再传递。

  2. 异步运行的时候,request会使用当前用户的身份,以及当前用户的语言

  3. 任务可在后台队列中查看运行情况。默认占用custom2-0队列中,也可以指定在其他队列中,方法为:

    root.call_script_async('zopen.xx:xxx', ztq_queue=’custom1-0’)
    
  4. 异步调用如果出错,可以进行重试。10秒后重试,最多重试3次,方法为:

    raise Retry(countdown=10, retries=3)
    
  5. 如果希望周期性永久重试,可以传递重试次数为-1:

    raise Retry(countdown=10, retries=-1)
    

3   内置异常

Unauthorized
没有权限
LogicError
友好的提示用户错误信息

4   内置变量

4.1   root 站点根对象

所有脚本都可以使用这个对象,具体的接口,内容库中 有介绍

4.2   ui 组件

ui是前端组件,具体参看 《前端开发》

4.3   web调用的运行环境

这个调用是从web发起的,会有如下内置变量。

4.3.1   context 上下文对象

请求地址中的上下文对象,也就是url地址中 @ 之前的对象地址

4.3.2   request请求

仅仅在web调用脚本中有这个内置变量。

客户端请求的所有信息

  • request.me.id:当前登录人
  • request.method: 请求的方法
  • request.me.groups: 当前登录人所在的组
  • request.get_token() 当前登录人的token认证信息
  • request.get_client_ip: 请求发起方的IP地址
  • request.form:表单信息,request.form[field_name]
  • request.bodyStream:请求内容,这个是StringIO类型,可以通过 request.bodyStream.read() 读取内容。
  • request['QUERY_STRING']:请求url里面的参数信息
  • request.getHeader('xxx') 读取请求消息头
  • reqeust.is_mobile() 是否手机浏览器访问
  • request.response是当前请求的返回信息:
  • request.response.setHeader('Content-Type', 'application/excel') #设置消息头
  • request.response.redirect(url, trusted=True) #跳转到另外一个地址

可以 print str(request) 得到所有的请求信息

4.3.3   view 当前页面

前端引擎中的当前页面,可进行页面操作,具体参看《前端开发》

5   Python代码沙箱

处于安全考虑,系统限制使用有限的一组类库,具体如下:

5.1   语法限制

  1. 禁止使用 _ 开头的变量、函数、方法

    _ 开头在Python中表示私有方法,禁止使用。

  2. class 关键字也是限制使用的

    定位为脚本级的开发,禁止使用class。

5.2   对print方法的重载

为了模拟在命令行的使用场景,我们提供print方法输出:

print(1)
print(2)

注意,所有print的结果,保存在一个 printed 局部变量中,通常通过如下方法输出:

return printed

由于printed是一个局部变量,下面的代码并不能正常工作:

def aaaa():
    print 1
    print 2

aaaa()
return printed

应该如下改写:

def aaaa():
    print 1
    print 2
    return printed

print aaaa()
return printed

5.3   string.Template 的改进

如果需要定制自己的ID和分割副,可以这样:

mytemplate = string.Template.new(template, idpattern='[_a-z][_a-z0-9\.:]*', delimiter=None)
result = mytemplate.safe_substitute(values)

5.4   可以使用的类库

诸如os等方法,是限制使用的

5.4.1   时间

  • time
  • pytz

5.4.2   数据处理

  • random
  • hashlib
  • hmac
  • re
  • Crypto.Cipher
  • jwt(PyJWT)

5.4.3   网络相关

  • urllib
  • urllib2
  • xmlrpclib
  • urlparse:
  • imaplib
  • ldap
  • davlib
  • cgi
  • email
  • HTMLParser
  • Soap协议 WSDL.Proxy

5.4.4   转换相关

  • xmltodict : xml转换为dict
  • binascii : 二进制转ascii
  • yaml/pyaml :yaml导出 , pyaml.dump 能导出更好的yaml格式
  • json : json转换,新增json.dumps2 和 json.loads2,更好支持时间类型
  • chardet :字符编码检测

5.4.5   数据库访问

  • cx_Oracle: oracle数据特有的驱动
  • transaction :事务管理

5.4.6   已经import,可内置使用的

  • datetime
  • calendar
  • excel文件的读写: xlwt, xlrd
  • StringIO

5.4.9   拼音处理pinyin

可以将汉字转换为拼音:

pinyin.hanzi2pinyin('我们')

可以根据拼音进行排序汉字:

pinyin.sortbypinyin(['张三', '李四', '张武'])

5.5   突破沙箱

如果你是独立部署,确信所有软件包都是安全的。 这时候,你希望能够import任意包,比如可以访问文件系统,使用ctypes等。

可以在控制台中设置 etcd:

/workonline/restrict_script_import    false

一旦设置这个开关,平台的脚本将可以import所有安装的python库。