Oracle UTL_HTTP 请求返回比在 Python 或 curl 中完成相同请求时更短的响应

Posted

技术标签:

【中文标题】Oracle UTL_HTTP 请求返回比在 Python 或 curl 中完成相同请求时更短的响应【英文标题】:Oracle UTL_HTTP request returns a shorter response than when the same request is done in Python or curl 【发布时间】:2021-02-25 18:21:20 【问题描述】:

我正在访问 REST 服务以进行数据查询和下载。这是执行身份验证的第一个调用。响应是一个包含身份验证令牌的 json 结构。

当我使用curl 拨打电话时...

$ curl -v -X POST $AUTH_URL \
   -H 'Content-Type: application/x-www-form-urlencoded' \
   -d 'apikey='$API_KEY'&grant_type=api_key&client_id=IDP'

...我得到以下响应。

首先是标题:

< server: IIS
< date: Thu, 25 Feb 2021 17:59:34 GMT
< content-type: application/json
< content-length: 1500
< x-content-type-options: nosniff
< x-xss-protection: 1; mode=block
< strict-transport-security: max-age=31536000; includeSubdomains;
< cache-control: no-store
< set-cookie: KC_RESTART=; Version=1; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Max-Age=0; Path=/auth/realms/IDP/; HttpOnly
< pragma: no-cache
< x-frame-options: SAMEORIGIN
< referrer-policy: no-referrer
< vary: Origin
< via: 1.1 google
< alt-svc: clear

还有内容:

"access_token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIxMThSRENzZTlqUWR4UVRnSkt2ZXlvSHBaaWE4R0pIVEU5RjJPSmE1M3N3In0.eyJleHAiOjE2MTQyOTAzNzQsImlhdCI6MTYxNDI3NTk3NCwianRpIjoiNzBkMmMwZGMtZWY3Yy00NDM5LWJiNmUtNmQ4MDEzZGU2YTU0IiwiaXNzIjoiaHR0cHM6Ly9hdXRoZW50aWNhdGUuZm91bmRhdGlvbi5hcGkub25lYXRsYXMuYWlyYnVzLmNvbS9hdXRoL3JlYWxtcy9JRFAiLCJhdWQiOiJJRFAiLCJzdWIiOiJmNmI0ZjVkNC0zMzZiLTRlMTctODc3Ni1jNjA1ZTczNTRjYmIiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJJRFAiLCJzZXNzaW9uX3N0YXRlIjoiODJkYWM4MjMtMTVios00MmVlLWE2YzEtZjg2ZDQ2MzY1ZjAzIiwiYWNyIjoiMSIsInNjb3BlIjoiIiwibmJmIjowLCJyb2xlIjoie1wiZ2VvLmlkcC5ub3RpZnlcIjpbXCJ1c2VyXCJdLFwiZ2VvLmFwcC5vYWRcIjpbXCJ1c2VyXCJdLFwiZ2VvLmlkcC5kYXRhc3RvcmVcIjpbXCJ1c2VyXCJdLFwiZ2VvLmFwcC53b3JrYmVuY2hcIjpbXCJ1c2VyXCJdfSIsInJvbGVzIjp7Imdlby5pZHAubm90aWZ5IjpbInVzZXIiXSwiZ2VvLmFwcC5vYWQiOlsidXNlciJdLCJnZW8uaWRwLmRhdGFzdG9yZSI6WyJ1c2VyIl0sImdlby5hcHAud29ya2JlbmNoIjpbInVzZXIiXX0sInN1aWQiOiIxMTg2NTEzNTQ2IiwidXVpZCI6Ijc5Yjg0MTZlLTY0NDYtNGMwYy1hODg1LWY1MzE2ZGMzOWMyZSIsImxvYSI6MTAwfQ.5W_E4fkhirbJZNAJ_TwMbLhcKdmnHBXOjvLUr4vW-DBRvSFfQrpdlDHLMIVI4B7bZ-OU_FVnH__i_diKYJFRH4l3Zqy8maa1pyj_WhZJksqBB69ehv8xx_3qtuJCZ0z0hln0FzmyG_Ep_uaru3gK_h33SuFxjdKr4F5XocyrYpGE-ewm-mBLj4DOBnZSJ4HgV0BG02LJIPIU8BybTmvgV-4mW3LXOVKDUJMmP4TF_ZEUzNz4a1vhoW4VIOvaNkk_8v8m_R4zjNOGmd_4jWEywORBZ1ofqvn72usY7TWEVpGBxR-rKYgzWXrdeBE4_l61MT420rBID9dbI2zRgEyVIQ","expires_in":14400,"refresh_expires_in":0,"token_type":"bearer","not-before-policy":0,"session_state":"82dac823-15b9-42ee-a6c1-f86d46365f03","scope":""

请注意,内容的长度是 1500。这也是 content-length: 1500 标头所说的内容。当我使用 Python 进行相同的测试时,我得到了相同的结果:1500 个字符的结果。

但是当我使用 Oracle UTL_HTTP 进行相同的测试时,结果只有 1453 个字符。这是从我的 PL/SQL 代码中调试的:

% resp.status_code=200
% resp.reason_phrase=OK
% resp.http_version=HTTP/1.0
% resp.get_headers
% .. Server: IIS
% .. Date: Thu, 25 Feb 2021 17:50:51 GMT
% .. Content-Type: application/json
% .. Content-Length: 1453
% .. X-Content-Type-Options: nosniff
% .. X-XSS-Protection: 1; mode=block
% .. Strict-Transport-Security: max-age=31536000; includeSubdomains;
% .. Cache-Control: no-store
% .. Set-Cookie: KC_RESTART=; Version=1; Expires=Thu, 01-Jan-1970 00:00:10 GMT;
Max-Age=0; Path=/auth/realms/IDP/; HttpOnly
% .. Pragma: no-cache
% .. X-Frame-Options: SAMEORIGIN
% .. Referrer-Policy: no-referrer
% .. Vary: Origin
% .. Via: 1.1 google
% .. Alt-Svc: clear
% Response:
"access_token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIxMThSRENzZT
lqUWR4UVRnSkt2ZXlvSHBaaWE4R0pIVEU5RjJPSmE1M3N3In0.eyJleHAiOjE2MTQyODk4NTEsImlhd
CI6MTYxNDI3NTQ1MSwianRpIjoiMDQ4ZjhlMjctZTgwZi00MjIyLWFmNDAtMjZlNDdmYTFhMDg0Iiwi
aXNzIjoiaHR0cHM6Ly8zNS4xOTAuNTkuNzkvYXV0aC9yZWFsbXMvSURQIiwiYXVkIjoiSURQIiwic3V
iIjoiZjZiNGY1ZDQtMzM2Yi00ZTE3LTg3NzYtYzYwNWU3MzU0Y2JiIiwidHlwIjoiQmVhcmVyIiwiYX
pwIjoiSURQIiwic2Vzc2lvbl9zdGF0ZSI6ImYzYmZlOGJiLTFiZGYtNDQ5OS04NDQwLWIxODk5OGYwY
jg5NiIsImFjciI6IjEiLCJzY29wZSI6IiIsIm5iZiI6MCwicm9sZSI6IntcImdlby5pZHAubm90aWZ5
XCI6W1widXNlclwiXSxcImdlby5hcHAub2FkXCI6W1widXNlclwiXSxcImdlby5pZHAuZGF0YXN0b3J
lXCI6W1widXNlclwiXSxcImdlby5hcHAud29ya2JlbmNoXCI6W1widXNlclwiXX0iLCJyb2xlcyI6ey
JnZW8uaWRwLm5vdGlmeSI6WyJ1c2VyIl0sImdlby5hcHAub2FkIjpbInVzZXIiXSwiZ2VvLmlkcC5kY
XRhc3RvcmUiOlsidXNlciJdLCJnZW8uYXBwLndvcmtiZW5jaCI6WyJ1c2VyIl19LCJzdWlkIjoiMTE4
NjUxMzU0NiIsInV1aWQiOiI3OWI4NDE2ZS02NDQ2LTRjMGMtYTg4NS1mNTMxNmRjMzljMmUiLCJsb2E
iOjEwMH0.XHwxx3TzNNwgzVMv18Jav4bqXW9Q4n2bP_HV1iy0K4VPH-w84tXsHjXfH_f05Ynn2CXqv-
rdHds6KtuZaI1aypNnIvNvmbUiNHd6M1geLY4w8Yy9rg9-WFjYiFXbLTP7vvUAMSHueJmeT6WvzAsUT
Z7IQdp0w5aLDQ6ElV8pX1khBMCC7uXedRRDK-UC1MlJBrWtbhIMu5MaqpdpPeBcBMCvmqUBFTFfW6dQ
Ko01jeDjxePz_gZ2wdyU8fkV8UNTzkS3i6PYUkcxi3pmEC5r93JSNGVRUsZ53y5IjcaJK4aRXvvZQzV
iOitsbu8Pfciii2E_NDlk3qYgSqlxVrmzNA","expires_in":14400,"refresh_expires_in":0,
"token_type":"bearer","not-before-policy":0,"session_state":"f3bfe8bb-1bdf-4499
-8440-b18998f0b896","scope":""

请注意,内容长度现在为 1453 个字符。不同之处在于 JSON 响应中的令牌信息。它应该是 1330 个字符,但只有 1283 个字符。 JSON 文档的其余部分是相同的。并且返回的令牌不再有效。

我找不到任何解释为什么从 UTL_HTTP 请求时响应更短。我首先认为它与字符集编码有关。我将所有内容都设置为 UTF-8。令牌以 base64 编码返回。

这是我使用的代码(我没有包含调试代码):

-- Setup the http request type and add the content
http_req := utl_http.begin_request(url, 'POST', 'HTTP/1.0');
utl_http.set_header(http_req, 'Content-Type', content_type);
utl_http.set_body_charset(http_req,'UTF-8');
utl_http.set_header(http_req, 'Content-Length', length(post_content));
utl_http.write_text(http_req, post_content);

-- Call the REST endpoint and fetch the http response
http_resp := utl_http.get_response(http_req);
utl_http.set_body_charset(http_resp,'UTF-8');

-- Read the response content
begin
  json_response := '';
  i := 0;
  loop
    utl_http.read_line(http_resp, response_line, false);
    json_response := json_response || response_line;
    i := i + 1;
  end loop;
exception
  when utl_http.end_of_body then
    utl_http.end_response(http_resp);
end;

我已经盯着这个问题看了好几个小时了。我尝试了各种方法,比如设置或不设置显式字符集编码,都没有效果。我看不出我做错了什么以及甲骨文为什么会对响应做任何事情。我可以想象它会出于某种原因截断它 - 但是为什么字符会从响应中 inside 中删除?

【问题讨论】:

应该有一些将缓冲区response_line传输到jsonjson_response的代码丢失 是的,确实如此。我从剪切和粘贴到问题中错过了它。然而它就在那里。我编辑了问题以将其包含在代码中。 找到了解释:我使用HTTP/1.0作为协议版本。一旦我将其从(或切换到HTTP/1.1)中删除,一切正常。 【参考方案1】:

我有点惭愧。答案很简单:在begin_request() 调用中,我明确指定了 HTTP 1.0 协议:

http_req := utl_http.begin_request(url, 'POST', 'HTTP/1.0');

一旦我摆脱了它(这意味着 Oracle 使用 HTTP 1.1 协议):

http_req := utl_http.begin_request(url, 'POST');

然后一切都开始正常工作:我现在从服务器获得完整的响应。

还有一个奇怪的地方,当我使用curl --http1.0 来强制使用 HTTP 1.0 时,我仍然得到了正确的答案。所以我假设在某些工作负载上使用 HTTP 1.0 时,Oracle 实现中存在一些问题。

【讨论】:

真的很奇怪,因为Content-Length是在服务器端确定的 是的,这很奇怪。我期待一个原始的curl --http1.0 会产生相同的效果,但它会返回正确的答案......真的很奇怪。

以上是关于Oracle UTL_HTTP 请求返回比在 Python 或 curl 中完成相同请求时更短的响应的主要内容,如果未能解决你的问题,请参考以下文章

请求 utl_http 包时 Oracle 错误“ORA-28759:打开文件失败”

对于使用 Oracle pl sql 的 http 请求,是不是有替代 utl_http 包的方法?

使用 ngixx 的 Oracle UTL_HTTP 错误请求

通过具有 78000 个字符的 Oracle 12c DB 使用 utl_http 请求 REST 调用正文

确定需要哪个证书才能使用 Oracle utl_http 执行 https 发布

Oracle 12c UTL_HTTP Cookie 值长度大于 1024