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 调用正文