赞
踩
常见的处理方法也许是创建创建database link,但dblink会对数据库性能造成影响(且会产生事务),而且不能传输大字段类型(如clob,bclob);
在不使用dblink的情况下如何实现呢?其实可以使用http请求实现,首先搭建一个http服务(post请求/get请求)返回需要的数据(返回数据类型可以是xml/json字符串,便于Oracle(xmltable/jsontable)解析),然后在Oracle语句块中请求对应服务进行操作便可。
HTTP GET方式:
- CREATE OR REPLACE FUNCTION FN_HTTP_GET (v_url VARCHAR2)
- RETURN VARCHAR2
- AS
- BEGIN
- DECLARE
- req UTL_HTTP.REQ;
- resp UTL_HTTP.RESP;
- v_line VARCHAR2 ( 4000 );
- v_text VARCHAR2 ( 4000 );
- BEGIN
- v_text := '';
- BEGIN
- req := UTL_HTTP.BEGIN_REQUEST ( url => v_url, method => 'GET' );
- UTL_HTTP.SET_BODY_CHARSET('UTF-8');
- UTL_HTTP.SET_HEADER(req, 'Content-Type', 'application/x-www-form-urlencoded');
- resp := UTL_HTTP.GET_RESPONSE ( req );
- LOOP
- UTL_HTTP.READ_LINE ( resp, v_line, TRUE );
- v_text := v_text || v_line;
- END LOOP;
- UTL_HTTP.END_RESPONSE( resp );
- UTL_HTTP.END_REQUEST( req );
- EXCEPTION
- WHEN UTL_HTTP.END_OF_BODY THEN
- UTL_HTTP.END_RESPONSE ( resp );
- WHEN OTHERS THEN
- UTL_HTTP.END_RESPONSE(resp);
- UTL_HTTP.END_REQUEST(req);
- END;
- return v_text;
- END;
- END;
HTTP POST方式:
- CREATE OR REPLACE FUNCTION FN_HTTP_POST (v_url VARCHAR2, v_body VARCHAR2, v_body_type VARCHAR2)
- RETURN VARCHAR2
- AS
- BEGIN
- DECLARE
- req UTL_HTTP.REQ;
- resp UTL_HTTP.RESP;
- v_line VARCHAR2 ( 4000 );
- v_text VARCHAR2 ( 4000 );
- BEGIN
- v_text := '';
- BEGIN
- req := UTL_HTTP.BEGIN_REQUEST ( url => v_url, method => 'POST' );
- UTL_HTTP.SET_BODY_CHARSET('UTF-8');
- UTL_HTTP.SET_HEADER(req, 'Content-Type', v_body_type);
- utl_http.set_header(req, 'Content-Length',lengthb(v_body));
- utl_http.write_text(req, v_body);
- resp := UTL_HTTP.GET_RESPONSE ( req );
- LOOP
- UTL_HTTP.READ_LINE ( resp, v_line, TRUE );
- v_text := v_text || v_line;
- END LOOP;
-
- UTL_HTTP.END_RESPONSE( resp );
- UTL_HTTP.END_REQUEST( req );
- EXCEPTION
- WHEN UTL_HTTP.END_OF_BODY THEN
- UTL_HTTP.END_RESPONSE ( resp );
- WHEN OTHERS THEN
- UTL_HTTP.END_RESPONSE(resp);
- UTL_HTTP.END_REQUEST(req);
- END;
- return v_text;
- END;
- END;
- CREATE OR REPLACE
- FUNCTION HTTP_REQUEST(
- v_url VARCHAR2,--请求地址
- v_param VARCHAR2,--POST 相当于表单提交
- v_body clob,--POST body中的参数
- v_type varchar2--类型
- )return varchar2 is
- req UTL_HTTP.REQ;
- resp UTL_HTTP.RESP;
- v_line VARCHAR2 (4000);
- v_text VARCHAR2 (4000);
- v_param_length NUMBER ;
- v_body_length NUMBER;
- buffer VARCHAR2(32767);
- offset NUMBER := 1;
- amount NUMBER := 32767;
- begin
- IF V_TYPE='GET' THEN
- v_text := '';
- req := UTL_HTTP.BEGIN_REQUEST ( url => v_url, method => 'GET' );
- UTL_HTTP.SET_BODY_CHARSET('UTF-8');
- UTL_HTTP.SET_HEADER(req, 'Content-Type', 'application/x-www-form-urlencoded');
- resp := UTL_HTTP.GET_RESPONSE ( req );
- UTL_HTTP.READ_LINE ( resp, v_line, TRUE );
- v_text := v_text || v_line;
- UTL_HTTP.END_RESPONSE( resp );
-
- ELSIF V_TYPE='POST_FORM' THEN
- v_param_length := LENGTHB(v_param);
- req := UTL_HTTP.BEGIN_REQUEST (url=> v_url, method => 'POST');
-
- UTL_HTTP.SET_BODY_CHARSET('UTF-8');
- UTL_HTTP.SET_HEADER (r => req,
- name => 'Content-Type',
- VALUE => 'application/x-www-form-urlencoded');
- UTL_HTTP.SET_HEADER (r => req,
- name => 'Content-Length',
- VALUE => v_param_length);
- UTL_HTTP.WRITE_RAW (r => req,
- data => UTL_RAW.CAST_TO_RAW(v_param));
- resp := UTL_HTTP.GET_RESPONSE(req);
- UTL_HTTP.READ_LINE(resp, v_text, TRUE);
- UTL_HTTP.END_RESPONSE(resp);
- ELSE
- v_body_length := dbms_lob.getlength(v_body);
- req := UTL_HTTP.BEGIN_REQUEST (url=> v_url, method => 'POST');
-
- UTL_HTTP.SET_BODY_CHARSET('UTF-8');
- UTL_HTTP.SET_HEADER (r => req,
- name => 'Content-Type',
- VALUE => 'application/json;charset=utf-8');
- UTL_HTTP.SET_HEADER (r => req,
- name => 'Content-Length',
- VALUE => v_body_length);
- --分段输出请求参数,这个header设置很重要
- UTL_HTTP.SET_HEADER (req, 'Transfer-Encoding', 'chunked');
- --分段输出请求参数,避免内容超出长度限制
- WHILE (offset < v_body_length) LOOP
- dbms_lob.read(v_body, amount, offset, buffer);
- UTL_HTTP.WRITE_RAW(r => req, data => UTL_RAW.CAST_TO_RAW(buffer));
- offset := offset + amount;
- END LOOP;
- resp := UTL_HTTP.GET_RESPONSE(req);
-
- UTL_HTTP.READ_LINE(resp, v_text, TRUE);
- UTL_HTTP.END_RESPONSE(resp);
- END IF;
- return v_text;
- EXCEPTION
- WHEN UTL_HTTP.END_OF_BODY THEN
- UTL_HTTP.END_RESPONSE ( resp );
- WHEN OTHERS THEN
- UTL_HTTP.END_RESPONSE(resp);
- UTL_HTTP.END_REQUEST(req);
- end;
网络正常,单http调用失败,无法调用时,可能是ACL控制未开启。
- select * from dba_network_acls;
- Select * From dba_network_acl_privileges ;
dba_network_acls为assign_acl维护进去的
dba_network_acl_privileges为create_acl和add_privilege维护进去的
如果dba_network_acl_privileges中有可用的记录,那么我们可以跳过create_acl这一步,直接使用存在的xml文件来新增权限;如果没有,那么我们就先创建一个acl
- --添加acl和权限控制,若已存在访问控制文件(ACL),可不用再创建
- begin
- dbms_network_acl_admin.create_acl ( -- 创建访问控制文件(ACL)
- acl => 'utl_http.xml', -- 文件名称
- description => 'HTTP Access', -- 描述
- principal => 'YBZNFK', -- 授权或者取消授权账号,大小写敏感
- is_grant => TRUE, -- 授权还是取消授权
- privilege => 'connect', -- 授权或者取消授权的权限列表
- start_date => null, -- 起始日期
- end_date => null -- 结束日期
- );
-
- --acl中给用户增加一个resolve的权限
- dbms_network_acl_admin.add_privilege ( -- 添加访问权限列表项
- acl => 'utl_http.xml', -- 刚才创建的acl名称
- principal => 'YBZNFK', -- 授权或取消授权用户
- is_grant => TRUE, -- 与上同
- privilege => 'resolve', -- 权限列表
- start_date => null,
- end_date => null
- );
-
- --acl中添加要访问的目标网址(ip和域名均可),可以指定端口范围
- dbms_network_acl_admin.assign_acl ( -- 该段命令意思是允许访问acl名为utl_http.xml下授权的用户,使用oracle网络访问包,所允许访问的目的主机,及其端口范围。
- acl => 'utl_http.xml',
- host => '*', -- 访问接口服务的ip地址或者域名,*代表所有
- lower_port => null, -- 允许访问的起始端口号
- upper_port => Null -- 允许访问的截止端口号
- );
- commit;
- end;
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。