如何从 11g Oracle (PL/SQL) 上的 URL 传递凭据和下载文件?

Posted

技术标签:

【中文标题】如何从 11g Oracle (PL/SQL) 上的 URL 传递凭据和下载文件?【英文标题】:How to pass credentials and download file from a URL on 11g Oracle (PL/SQL)? 【发布时间】:2016-01-06 16:19:09 【问题描述】:

我正在尝试编写一个 plsql 过程来从另一个系统中的给定 url 下载文件。该系统需要用户名和密码才能访问。当我尝试以下程序时(基本上是这个script),我收到一个错误:

ORA-06502:PL/SQL:数字或值错误:十六进制到原始转换错误

它来自这条线:utl_http.set_header(l_http_request, 'Authorization', 'Basic ' || utl_encode.base64_encode('userid:passwd')); 我添加它以传递凭据。

如果我评论它,这个错误就会消失,但我得到:Authorization Required.This server could not verify that you are authorized to access the document requested."

程序代码为:

CREATE OR REPLACE PROCEDURE APPS.load_binary_from_url (p_url  IN  VARCHAR2) AS 
  l_http_request   UTL_HTTP.req;
  l_http_response  UTL_HTTP.resp;
  l_blob           BLOB;
  l_raw            RAW(32767);
  l_url            VARCHAR2(300); 

BEGIN
  -- Initialize the BLOB.
  DBMS_LOB.createtemporary(l_blob, FALSE);  
  l_url :=p_url; 

  -- Make a HTTP request and get the response.
  l_http_request  := UTL_HTTP.begin_request(l_url); 
  utl_http.set_header(l_http_request, 'Authorization', 'Basic ' || utl_encode.base64_encode('userid:passwd'));
  l_http_response := UTL_HTTP.get_response(l_http_request);

  -- Copy the response into the BLOB.
  BEGIN
    LOOP
        UTL_HTTP.read_raw(l_http_response, l_raw, 32767);
        DBMS_LOB.writeappend (l_blob, UTL_RAW.length(l_raw), l_raw);
    END LOOP;
  EXCEPTION
    WHEN UTL_HTTP.end_of_body THEN
      UTL_HTTP.end_response(l_http_response);
  END;

  -- Insert the data into the table.
  INSERT INTO http_blob_test (id, url, data)
  VALUES (http_blob_test_seq.NEXTVAL, p_url, l_blob);
  COMMIT;

  -- Relase the resources associated with the temporary LOB.
  DBMS_LOB.freetemporary(l_blob);
EXCEPTION
  WHEN OTHERS THEN
    UTL_HTTP.end_response(l_http_response);
    DBMS_LOB.freetemporary(l_blob);
    RAISE;
END load_binary_from_url;
/

【问题讨论】:

【参考方案1】:

utl_encode.base64_encode function 采用 RAW 参数,而不是 VARCHAR2,因此您必须先转换值。您可以在纯 SQL 中看到相同的内容(消息略有不同):

select utl_encode.base64_encode('userid:passwd') from dual;

SQL Error: ORA-01465: invalid hex number

您可以使用utl_i18n.string_to_raw function 将字符串转换为RAW:

select utl_encode.base64_encode(utl_i18n.string_to_raw('userid:passwd', 'AL32UTF8'))
from dual;

UTL_ENCODE.BASE64_ENCODE(UTL_I18N.STRING_TO_RAW('USERID:PASSWD','AL32UTF8'))   
--------------------------------------------------------------------------------
64584E6C636D6C6B4F6E426863334E335A413D3D                                        

取决于您的客户端和设置,可能显示如上或隐式显示从原始转换回来;例如SQL Fiddle 将其显示为ZFhObGNtbGtPbkJoYzNOM1pBPT0=。但是连接它会使其保持原始形式。

您需要另一个步骤来显式转换为可用的字符串值:

select utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_i18n.string_to_raw('userid:passwd', 'AL32UTF8'))) from dual;

UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(UTL_I18N.STRING_TO_RAW('USERID
--------------------------------------------------------------------------------
dXNlcmlkOnBhc3N3ZA==                                                            

然后与Basic 前缀连接时保留相同的值。

你可以在你的程序中做同样的事情:

  utl_http.set_header(l_http_request, 'Authorization',
    'Basic ' || utl_raw.cast_to_varchar2(utl_encode.base64_encode(
      utl_i18n.string_to_raw('userid:passwd', 'AL32UTF8'))));

...为了便于阅读,可以选择将 RAW 值首先存储在它们自己的变量中。

【讨论】:

嗨,亚历克斯,你完全正确。这已经摆脱了错误。但我仍然无法获取文件。我收到一个带有“需要授权。此服务器无法验证您是否有权访问所请求的文档”的 htm 文件。 (我已经通过浏览器验证了我正在使用的用户 ID) @manumuraleedharan - 是的,错过了您需要将 RAW 结果转换回字符串。更新了答案以表明这一点。您可能需要检查手动请求的标头(通过浏览器的开发人员工具),以将您获得的 HTTP 标头与生成的 HTTP 标头进行比较。 优秀的@AlexPoole 你又为我节省了时间!问候【参考方案2】:

我今天遇到了同样的问题,使用以下方法解决了它:

  utl_http.set_header(l_http_request, 'Authorization',
    'Basic ' || utl_raw.cast_to_varchar2(utl_encode.base64_encode(
      utl_i18n.string_to_raw('userid:passwd', 'UTF8'))));

注意:我使用的是 Oracle Database EE 11GR2

【讨论】:

以上是关于如何从 11g Oracle (PL/SQL) 上的 URL 传递凭据和下载文件?的主要内容,如果未能解决你的问题,请参考以下文章

从 pl/sql 中的函数返回数据作为光标而不创建类型 oracle 11g

Oracle 11g 代码上的 PL/SQL 是在执行存储过程时

用于 oracle 11g 的 PL/SQL 中的嵌入式脚本 [重复]

PL/SQL32位连接Oracle 11g64位

在 Oracle 11g Express Edition 中运行 PL/SQL 代码 - 错误

如何使用参数从 Oracle PL/SQL 执行 Java jar 文件?