LoginSignup
5
0

More than 1 year has passed since last update.

requestでPOSTした送信内容(data)を確認したい!

Last updated at Posted at 2022-09-08

背景

PythonでコーディングしていくうえでRequestsモジュールを利用し、Webコンテンツを取得したりWebAPIを叩いたりするケースがあります。
これまではその時の実際のrequestの内容までは、あまり確認したいというケースはありませんでした。
そりゃぁそうです。自分でHeaderやBodyのデータを自分でセットしているんですから、それを確認すれば良いんです。
そしてWebブラウザ上でJavaScriptとかから送信している場合は、Chromeのデベロッパーツールを使えばPOST通信時に送信したパラメータは簡単に確認できます。

今回、訳あってRequestsモジュールで実際に送っているデータを確認する方法を探したのですが、無いのです! 有ってもおかしくはない機能かと思うのですが、見つかりません!!
本当に無いの?? 私が探し当てられなかっただけなの??

Requests.session.get('body') こんな感じで、取得できたら良かったのですが…
できなかった…
(だれか、知っている人がいらっしゃいましたら… おせーてくださいませ)

そんなわけで…

まぁ、無いなら自分のWebサーバーに向けてrequestして、そのデータを見れば良いでしょう…
と、思ったのですが、なんだかわざわざFlaskを使ってアプリを書くのも面倒で、世の中の人はどう実現しているのか探ってみたところ、
もう… これでしょ! という事例が見つかりましたぁ。

 『curlのGET,POSTのデータを確認https://qiita.com/tkj/items/210a66213667bc038110

を参考にさせてもらいました。ありがとうございます。

この方法であれば、わざわざサーバーを使う必要なく、手元(ローカル)の環境で確認ができます。簡単簡単!!

やってみましょう。

なぜそこまでして、requestの内容を確認したかったかというと…
業務の自動化を図るために、社内のWebシステムにファイルをアップロードする仕組みを作っています。この仕組みは、WebAPIとして稼働していて、ビジネスロジックを担当するアプリケーションが、BLOBでファイルをこのWebAPIに渡してくれると、このWebAPIが社内のWebシステムにファイルをアップロードするというものです。

社内のWebシステムにはいろいろ"仕来り"がありますので、その辺をWebAPIが担当し、アプリケーションは簡単に社内のWebシステムにアップロードできるようなカラクリにしています。

image.png

この時、社内のWebシステムは"multipart/form-data"で受けるようになっています。
なので、ローカルのファイルであれば、こんな感じでアップロードできることは確認しています。

import Requests
URL      = 'https://社内のWebシステム.com/アプリ/アップロード/'
FILES       = {'{{FORM_NAME}}': open('アップロードするファイルのPATH', 'rb')}
response = requests.post(URL, files=FILES)

しかし、WebAPIはビジネスロジック(アプリケーション)から受けたBLOBを、テンポラリファイルとして保存はしたくはないのです。
せっかくWebAPIはBLOBとして受けているのですから、そのまま io.BytesIO(ファイルの内容) でファイルとして扱いたいじゃないですか??

import Requests
URL      = 'https://社内のWebシステム.com/アプリ/アップロード/'
FILES       = {'{{FORM_NAME}}': io.BytesIO(ファイルの内容)}
response = requests.post(URL, files=FILES)

open('アップロードするファイルのPATH', 'rb')でファイルオブジェクトを指定しているんだから、io.BytesIO(ファイルの内容)も同じでしょ! と思ったんですがね。
でも、これだと… なんだか上手くいかないんですよぉ…

なので表題の件である、「requestの内容」を確認し、open('アップロードするファイルのPATH', 'rb')io.BytesIO(ファイルの内容)での、requestの違いを確認したかったのです!

参考にさせていただいた『curlのGET,POSTのデータを確認』では、ファイルのようなバイナリデータをrequestするとちょっと都合が悪かったので、その辺なんかに手を加えています。

echoRequestsHttpServer.py
import http.server
from urllib.parse import urlparse, parse_qs

class MyHandler(http.server.BaseHTTPRequestHandler):
    def do_POST(self):
        self.make_data()
    def do_GET(self):
        self.make_data()
    def make_data(self):
        req_method    = self.command
        req_parsed    = urlparse(self.path)
        req_params    = '{}'.format(parse_qs(req_parsed.query))
        req_head      = '\n{}'.format(self.headers)
        length        = self.headers.get("content-length")
        content_len   = int(length) if length else 0
        _req_body     = self.rfile.read(content_len)
        req_body      = '{}'.format(_req_body)
        # レスポンスデータ生成
        body  = '== リクエストデータ ====================\n'
        body += 'method: ' + req_method + '\n'
        body += 'header: ' + req_head   + '\n'
        body += 'params: ' + req_params + '\n'
        body += 'body  : ' + req_body   + '\n'
        body += '================================\n'
        # サーバーの標準出力
        print('== リクエストデータ ====================')
        print('【METHOD 】', req_method)
        print('【HEADERS】', req_head)
        print('【PARAMS 】', req_params)
        print('【 BODY  】', req_body)
        print('================================')
        # レスポンス
        self.send_response(200)
        self.send_header('Content-type', 'text/html; charset=utf-8')
        self.send_header('Content-length', len(body.encode()))
        self.end_headers()
        self.wfile.write(body.encode())
host = '0.0.0.0'
port = 5001
httpd = http.server.HTTPServer((host, port), MyHandler)
print('ポート:%s' % port)
httpd.serve_forever()

このサーバーを起動すると…

% python echoRequestsHttpServer.py
ポート:5001

そして、上手くアップロードできない、対象のrequestをこのサーバーに向けてrequestすると…

== リクエストデータ ====================
METHOD  POST
HEADERS
user-agent: Takky_API
Accept-Encoding: gzip, deflate
Accept: application/json, text/javascript, */*; q=0.01
Connection: keep-alive
Content-Length: 1163
Content-Type: multipart/form-data; boundary=0c0acc9c1affeddfa38401805492e8f5

PARAMS  {}
 BODY   b'--0c0acc9c1affeddfa38401805492e8f5\r\n        ※みやすくするため改行してます
                   Content-Disposition: form-data; name="{{FORM_NAME}}";
   ※ココ →     filename="{{FORM_NAME}}"\r\n\r\n
#                  ^^^^^^^^
                   "ファイルの内容"\r\n\r\n
                   --0c0acc9c1affeddfa38401805492e8f5--\r\n'
================================
192.168.40.136 - - [15/Aug/2022 18:14:23] "POST / HTTP/1.1" 200 -

問題なくアップロードできる、ローカルファイルをアップロードするrequestだと…

== リクエストデータ ====================
METHOD  POST
HEADERS
user-agent: Takky_API
Accept-Encoding: gzip, deflate
Accept: application/json, text/javascript, */*; q=0.01
Connection: keep-alive
Content-Length: 1145
Content-Type: multipart/form-data; boundary=c53e52730b147a1a87e3452b37f5dc27

PARAMS  {}
 BODY   b'--c53e52730b147a1a87e3452b37f5dc27\r\n        ※みやすくするため改行してます
                   Content-Disposition: form-data; name="{{FORM_NAME}}";
    ※ココ →    filename="{{アップロードするファイルのファイル名}}"\r\n\r\n
#                  ^^^^^^^^^^^^^^^^^^
                   "ファイルの内容"\r\n\r\n
                   --c53e52730b147a1a87e3452b37f5dc27--\r\n'
================================
192.168.40.136 - - [15/Aug/2022 18:13:21] "POST / HTTP/1.1" 200 -
わかりましたぁ!!!!!!

ちゃんと、確認できれば簡単にわかることでした。

"※ココ →"で示されているように、open('アップロードするファイルのPATH', 'rb')でファイルを渡している場合は、bodyの「filename」に open() したファイル名がセットされていますが、io.BytesIO(ファイルの内容)で渡している場合には「filename」に "FORM_NAME" と同じ値が渡されています。

そうですねぇ… 「filename」は渡さなきゃイカンですよね!?
なので、「filename」も渡してあげるように修正します。

URL      = 'https://社内のWebシステム.com/アプリ/アップロード/'
FILES       = {'{{FORM_NAME}}': ('アップロードするファイルのファイル名',io.BytesIO(ファイルの内容))}
#                                                     ^^^^^^^^^^^^^^^^^^                                             ^
response = requests.post(URL, files=FILES)

これで、WebAPIは社内のWebシステムに、テンポラリファイルを介すことなくファイルをアップロードすることができました。

やはり、「百聞は一見にしかず」です。
横着をせずにちゃんと状況を"正確に"把握することが、いろいろ近道につながります。

めでたしめでたし…

5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0