テキストファイルの読み取り(XMLHTTP編)

VBAを使い「テキストファイルを読み書き」する手法について、以下のようなシリーズで紹介しています。
①テキストの文字コードについて
②Openステートメント法による読み書き
③ADODB.Stream法による読み書き
④TextStream法による読み書き
⑤XMLHTTP法によるWebデータの読み取り ←今回
⑥Web上からダウンロードしての読み取り
XMLHTTPオブジェクトは、HTTP通信を使ってWebサーバーに対してリクエスト(データの要求)を行い、レスポンス(応答)してきたデータを受け取る機能を持っています。この機能を使うことで、Webサーバー上にあるテキストファイルの内容を読み取ることができます。今回はこのXMLHTTP法を紹介します。
この「XMLHTTP法」は基本的には文字コードUTF-8のみの対応ですが、ADODB.Stream等と組み合わせる事で複数の文字コードに対応できます(下表)。なお操作可能なのは、Web上(http:// や https:// で始まる場所)のファイルのみです。
読み書き手法 | 対応文字コード | ファイルの場所 | ||||
---|---|---|---|---|---|---|
Shift-JIS | UTF-8 | UTF-16 | LAN上 | Web上 | ||
② | Openステートメント | 〇 | △ | 〇 | ||
③ | ADODB.Stream | 〇 | 〇 | 〇 | 〇 | |
④ | TextStream | 〇 | 〇 | 〇 | ||
⑤ | XMLHTTP | (〇) | 〇 | (〇) | 〇 |
上表のようにXMLHTTPオブジェクトのみでは、文字コード面では「UTF-8」が一応標準となっているようです。一応というのは図22のように、BOM付きであればUTF-16もresponseTextプロパティで読み込み出来ますし、逆にWinHttp.WinHttpRequestオブジェクトを使うとASCII以外はresponseTextでは文字化けしてしまいます。
但しXMLHTTPオブジェクトは、responseTextプロパティでテキスト文字を取得する以外にも、responseBodyプロパティで「バイナリデータ」として受け取る事ができますので、そのバイナリデータをADODB.Stream法などを使う事で様々な文字コードに対応することが可能であるため、カッコ付きとしました。
手法全体の話ですが、図01のように手法ごとに「対応できる文字コードが異なる」原因の1つとして、手法の生まれた時期と関係がありそうです。下図は各手法の歴史です。
今回紹介するXMLHTTPは、下表のように1999年にInternet Explorer(IE5)に実装されたのを皮切りに、他のブラウザにも展開されていきました。Microsoftが実装しているので、おそらく同じ時期からVBAでも使用が可能になったのではと推測されます。

図02
同様に各文字コードの歴史をまとめたのが下図です。XMLHTTPが生まれた頃には全ての文字コードが出揃っていますが、その少し前にWindows95が発売され、自宅のPCがインターネット先のサーバー(主にUNIX)と繋がる時代となりました。
しかしWindowsとUNIX(文字コードはEUC)では文字コードが異なるため文字化けを起こしてしまいます。そこで世界共通で使用できるUnicodeが台頭するのですが、特にXMLHTTPはインターネット上のファイルを操作するものなので、UTF-8(Unicodeの中でも、UTF-8はファイルサイズを必要最小限に抑えられる)を標準とする必要があったのではないかと思われます。

図03
1.XMLHTTPオブジェクト
このページを見ている方は、恐らくブラウザを使って閲覧していると思います。御存知のように、ブラウザ上部のアドレスバーにURLを入力(または他サイトのリンクをクリック)することで、内容がブラウザに表示されます。今回のコード例で使用するテキストファイルの1つ「Test_UTF8B.txt」で試してみると、以下のように表示されます。

図04
このURLを入力してからデータを取得するまでの流れを、クライアント(ユーザー)側とサーバー側とのやり取りで表したのが以下です。

図05
クライアント側からサーバー側にリクエスト(要求)をするには「HTTPリクエスト」を送ります。このHTTPリクエストは3領域に分かれており、リクエストしたファイルのURLはリクエストラインに書かれます。
そのHTTPリクエストを受け取ったサーバーは、対象ファイルのデータを書き込んだ「HTTPレスポンス」をクライアント側に戻します。HTTPレスポンスを受け取ったクライアントは、データを取り出してブラウザ上に表示させます。
この「データをリクエストし、サーバーからデータを受け取る」というのが、XMLHTTPオブジェクトの機能です。
![]() 今回のオブジェクトは、以下のように色々な名前で呼ばれているようです。 ① XMLHTTPRequestオブジェクト ② XMLHTTPオブジェクト ③ IXMLHTTPRequestオブジェクト ①~③の間には上下関係があると説明しているサイトもありますが、恐らくオブジェクトの正式な呼び方は決まっているのだろうと思います。しかし作成者であるMicrosoftのサイトを色々見ても、スッキリとした答えは得られていません。調べた時のイメージとしては、Javascriptでは①で呼ばれ、VBAでは②で呼ばれているような感じです。 また③のIXMLHTTPRequestはインターフェースであると説明しているサイトもありますが、生成されたオブジェクトをVBEのウォッチウィンドウなどで確認すると「Object/IServerXMLHTTPRequest2」のように表示されることから、最も正式名称に近いのでは?と私の中では勝手に方向付けています。 どの呼び名にしても、機能としては「HTTP通信でサーバーからデータを取得」するものです。ここではXMLHTTPオブジェクトと呼ぶことにしました。 |
1ー1.XMLHTTPオブジェクトの生成
XMLHTTPオブジェクトをVBAで使うには、まずオブジェクトを生成する必要があります。その生成方法には以下の2種類があります。「事前バインディング」・・・コードを実行する前に生成
「実行時バインディング」・・コードを実行した時に初めて生成
事前バインディングの特徴は、コード作成時にインテリセンス(コード補完機能=使用可能なプロパティ等が表示され、選択することが可)が使える事と併せ、効率が良い(≒実行速度が速い)ことです。
一方実行時バインディングは、実行しているPCに合わせたライブラリを呼び出すため、PC環境の異なる複数ユーザーにマクロを配布する時でも安全度は高いと思われます。
1ー1ー1.事前バインディング
事前バインディングは、VBE(コードを書くウィンドウ)上部の「ツール」→「参照設定」から、図06のように・Microsoft XML, v6.0 (MSXML(XMLファイルを構文解析するためのプログラム)のバージョン6 )
・Microsoft XML, v3.0 (MSXMLのバージョン3 )
・Microsoft WinHTTP Servers, version 5.1 (WinHTTP(ネットワーク上でHTTP通信を行うプログラム))
のどれかにチェックをし、有効にします(通常は「Microsoft XML, v6.0」で良いと思います)。

図06
「ライブラリーを参照設定」した上で、プログラム的には図07のように「オブジェクト変数をXMLHTTPオブジェクトとして宣言」→「New句を使って生成」します。
- '========== ⇩(1) 事前バインディングでの宣言と生成 ============
- Dim XHR As ServerXMLHTTP60 '←XMLHTTPオブジェクト型変数の宣言
- Set XHR = New ServerXMLHTTP60 '←XMLHTTPオブジェクトの生成
- (作成したXMLHTTPオブジェクト変数(XHR)を使い、テキスト処理)
01行目「Dim XHR As ServerXMLHTTP60」で、XMLHTTPオブジェクト型で変数宣言をします。
03行目「Set XHR = New ServerXMLHTTP60」では、New句を使ってXMLHTTPオブジェクトを生成します。
オブジェクト作成後は、そのオブジェクト変数(図07では、XHR )を使って処理作業を行います。
なお01行目を「Dim XHR As Object」と一般Object型で宣言したとしても、03行目で生成されるXHR変数は「XMLHTTPオブジェクト型」になってくれます。
ライブラリ参照設定をすると、ライブラリに対応したデータ型のオブジェクトが選択できるようになります。図07では「ServerXMLHTTP60」を指定していますが、参照設定したライブラリと使用できるオブジェクトとの対照表は以下のようになります。なお、オブジェクト型の先頭「MSXML2.」「WinHttp.」は無くてもOKです。
参照設定するライブラリ | オブジェクト型 |
---|---|
Microsoft XML, v6.0 | ・MSXML2.ServerXMLHTTP60 ・MSXML2.XMLHTTP60 |
Microsoft XML, v3.0 | ・MSXML2.ServerXMLHTTP30 ・MSXML2.ServerXMLHTTP ・MSXML2.XMLHTTP30 ・MSXML2.XMLHTTP |
Microsoft WinHTTP Servers, version 5.1 | ・WinHttp.WinHttpRequest |
![]() 図07では、ServerXMLHTTP60をデータ型として指定しました。しかしMSXML2には「XMLHTTP60」のように"Server"というのが付いていないオブジェクト型があります。 このServerが付いたものと付かないものでは使えるメソッドの種類が異なり、またバージョンによっても異なるようなので下表にまとめました。同時にWinHttpRequestについても併記しています。
*1印をつけた「setProxy」「setProxyCredentials」は、MSXML2.ServerXMLHTTP30オブジェクトの配下には存在しないメソッドなのですが、生成するとServerXMLHTTP30オブジェクトは「IServerXMLHTTPRequest2 オブジェクト」となり、その下で setProxy・setProxyCredentials メソッドは機能するようです。 一方、XMLHTTP30オブジェクトも生成後はIServerXMLHTTPRequest2オブジェクトになるのですが、setProxy・setProxyCredentials メソッドは使用できません。生成後が同じオブジェクト名でも、宣言時がServer系か否かで使えるメソッドが異なるのは複雑というか理解に苦しみます。 上表を見るとMSXMLでは、「Microsoft XML, v6.0」を参照設定し「ServerXMLHTTP60」をデータ型としてオブジェクト生成した時が、最も多くのメソッドが使用できることが分かります(プロパティは、どれを使っても変わらないようです)。 一方「WinHttp.WinHttpRequest」には、独自のプロパティ(option)・メソッド(setAutoLogonPolicy等)があるようです。 |
1ー1ー2.実行時バインディング
実行時バインディングの場合は、CreateObject関数を使ってXMLHTTPオブジェクトの生成をします。- '========== ⇩(2) 実行時バインディングでの宣言と生成 ============
- Dim XHR As Object '← 一般オブジェクト型変数の宣言
- Set XHR = CreateObject("MSXML2.ServerXMLHTTP.6.0") '←XMLHTTPオブジェクトの生成
- (作成したXMLHTTPオブジェクト変数(XHR)を使い、テキスト処理)
21行目「Dim XHR As Object」では、単なるObject型として変数宣言をします。
23行目「Set XHR = CreateObject("MSXML2.ServerXMLHTTP.6.0")」では、CreateObject関数を使ってXMLHTTPオブジェクトを生成します。
![]() 23行目でCreateObject関数に渡している引数は「"MSXML2.ServerXMLHTTP.6.0"」としています。XMLHTTPオブジェクトを生成する場合、この引数(オブジェクトのアプリケーション名+クラス名)を様々な値に設定する事が可能です。 下記ではCreateObject関数に設定可能な値と、それに必要なライブラリファイル名を示します。見え消しで無いのが設定可能のものです(PCの環境により、異なる可能性がありますので御注意下さい)。 なお、対応するライブラリファイル名は私の推定です。
クラス名の後ろの数字はバージョンを表します。例えば「MSXML2.ServerXMLHTTP.6.0」は最新のバージョン6.0です。 バージョンの内「5.0」「4.0」は、現在ではMicrosoftの方でバグ修正が行われない状態となっており、最新のO/Sには対応するライブラリファイルもインストールされていない様です。 但しバージョン「3.0」については現役で、広範囲に利用されているようです。なおバージョンを省略(表の5番や11番)すると、バージョン3.0と判断されるようです。 またアプリ名を表す接頭辞には、「MSXML2」「Microsoft」「WinHttp」の3種類があります。 Microsoft接頭辞は古いため「使わない方が良い」と説明しているサイトも見かけますが、一応正しく動きます。 |
![]() 「よりみち」で説明したように、事前バインディングの時にもServerXMLHTTPとXMLHTTPの違いがありましたが、実行時バインディングにも図11のように「Server」という文字が付くもの(No.1~6)と、付かないもの(No.7~11)があります。またNo.14「WinHttp.WinHttpRequest.5.1」のように、少し種類の違うものもあります。 No.1~11は「MSXML(Microsoft XML)」で、且つServerの付くもの(例えば "MSXML2.ServerXMLHTTP")は、異なるWebサーバー間でのアクセス用、また付かないもの(例えば "MSXML2.XMLHTTP")は、クライアント側からサーバーにアクセスし、サーバー上のドキュメントを取得するためのものと説明されています。 またNo.14は「WinHTTP(Window HTTP Services)」の一部で、MSXMLと同様にHTTPリクエスト送信ができます。 このオブジェクトの違いは使用できるプロパティ・メソッドに現れ、事前バインディングの時(図09)とほぼ類似した分類になります。なお図11の右端列には「A・B・C」とその分類記号を記しました。
A列は図09の「ServerXMLHTTP60」列と同じとなり、B列は「XMLHTTP30/60」列と同じという結果になりました。また「Microsoft.XMLHTTP」は「MSXML2.XMLHTTP」の仲間のようです。 一方C列は図09の「WinHttp.WinHttpRequest」列と同じです。 なお、頭に"Server"が付く・付かないについては「TLSのバージョンの対応範囲が異なる」という下記情報もあります。 ・Serverが付かないクラスはTLS 1.2に非対応なので、TLS 1.2を使ってるサイトではエラーが出る ・Server付きのクラスはTLS 1.2に対応しているため、TLS 1.2を使ってるサイトでも繋がる TLS(Transport Layer Security)はSSL(Secure Sockets Layer)の後継で、通信の暗号化と認証の機能を持つセキュリティプロトコルです。この現象について色々と調べたり試したりしてみたのですが、TLSのバージョンはO/S自身で決まるはずですので、現在使用されているWindows(10以降)では大丈夫そうですし、試した限りでもエラーが出るような現象は確認されませんでした。 |
1ー2.設定項目とオブジェクトの関係
図09および図12では、生成するオブジェクト毎に使用できるプロパティ・メソッドを示しました。しかし一つのプロパティ・メソッドが複数の機能を果たすものもあるため、「各機能がオブジェクトのどのプロパティ・メソッドで実現できるか」を整理してみました。なお各オブジェクト名が、事前バインディングと実行時バインディングとではほぼ一緒なので、集合させた形としました。またOpen・Send・Abortは、どのオブジェクトでも基本となるメソッドですし、onreadystatechangeメソッドはイベントの機能なので、表からは除外しています。
まずは設定項目についてまとめたのが以下になります。
設定項目 | MSXML2 | Micro | Win | ||
---|---|---|---|---|---|
Server | XML | XML | Win | ||
ヘッダ | |||||
リクエストヘッダ | setRequest | setRequest | setRequest | ||
応答ヘッダのサイズ | Option | ||||
URL等 | |||||
URLの文字コード | setOption | Option | |||
URLの%文字のエスケープ | setOption | Option | |||
不安全文字のエスケープ | Option | ||||
時間 | |||||
タイムアウト | setTimeouts | setTimeouts | |||
レスポンス待ち時間 | waitFor | waitFor | |||
リダイレクト | |||||
自動リダイレクト | Option | ||||
HTTPへのリダイレクト | Option | ||||
リダイレクト最大数 | Option | ||||
証明書 | |||||
クライアント証明書 | setOption | setClient Option | |||
サーバー証明書エラーのマスク | setOption | Option | |||
証明書失効チェック | Option | ||||
Passport認証 | Option | ||||
HTTP/1.1の使用 | Option | ||||
承認状態を戻す | Option | ||||
サーバー | |||||
プロキシ設定 | setProxy | setProxy | |||
プロキシのID・PW | setProxy | set | |||
WebサーバーのID・PW | setCredentials | ||||
自動ログオンポリシー | setAuto | ||||
パスワード拒否 | Option | ||||
他 | |||||
ユーザーエージェント | Option | ||||
トラフィック監視 | Option | ||||
再接続のサイズ | Option |
次に取得情報が以下です。
取得情報 | MSXML2 | Micro | Win | ||
---|---|---|---|---|---|
Server | XML | XML | Win | ||
状態 | |||||
オブジェクトの進行状態 | readyState | readyState | |||
やり取りの状態 | status statusText | status statusText | status statusText | ||
取得データ | |||||
テキストデータ | response | response | response | ||
バイナリデータ | response | response | response | ||
Stream | (response | (response | (response | ||
XMLデータ | response | response | |||
ヘッダ | |||||
ヘッダ情報 | getAll getResponse | getAll getResponse | getAll getResponse | ||
応答ヘッダのサイズ | Option | ||||
URL等 | |||||
URL | getOption | Option | |||
URLの文字コード | getOption | Option | |||
URLの%文字のエスケープ | getOption | Option | |||
不安全文字のエスケープ | Option | ||||
リダイレクト | |||||
自動リダイレクト | Option | ||||
HTTPへのリダイレクト | Option | ||||
リダイレクト最大数 | Option | ||||
証明書 | |||||
クライアント証明書 | getOption | ||||
サーバ証明書エラーのマスク | getOption | Option | |||
証明書失効チェック | Option | ||||
Passport認証 | Option | ||||
HTTP/1.1の使用 | Option | ||||
承認状態を戻す | Option | ||||
サーバー | |||||
パスワード拒否 | Option | ||||
他 | |||||
ユーザーエージェント | Option | ||||
トラフィック監視 | Option | ||||
再接続のサイズ | Option |
表の各列を見比べると、最も充実しているように見えるのは「WinHttp.WinHttpRequest」で、多くの機能を有しているのはOptionプロパティです。
また「WinHttp.WinHttpRequest」にはreadyStateプロパティが無いので、非同期ではレスポンス完了が受け取れないような印象がありますが、waitForResponseメソッドを使えば問題なく受け取れる(図52参照)ので、そこはマイナス点とする必要は無いかと思います。
なおオブジェクトが使われる想定環境としては、「ServerXMLHTTP」と「WinHttpRequest」はサーバー~サーバー間、「XMLHTTP」はクライアント~サーバー間のようです。ですのでPC(=クライアント)~サーバーでのやり取りだけを考えれば、基本的には「XMLHTTP」のみで用は足りるものと思われます。
1ー3.サンプルコード内で使用しているWeb上のファイルについて
以下の説明内で使っているサンプルコードは、Web上に存在するテキストファイルを取得し表示する内容になっています。実際にサンプルファイルが動く為には、その「Web上のファイル」が実在する必要があり、ここでは本サイト上に以下の内容のファイルを置いています。特に意味のあるファイルではありませんが、文字コードが違うとどうなるか等を試すには必要かと思い、内容は漢字・数字・アルファベット・半角カナ・ひらがなを含めたものにしています。
URL:https://atsumitm.iobb.net/its/excel/ [下表のファイル名]
ファイル名 | 文字コード | BOM | 内容 | ||||||
---|---|---|---|---|---|---|---|---|---|
Test_SJIS.txt | Shift-JIS | - | "Aアあ123" "Web上のファイル" "文字コード〇〇(BOM有無)" | ||||||
Test_UTF8N.txt | UTF-8 | 無し | |||||||
Test_UTF8B.txt | UTF-8 | 付き | |||||||
Test_UTF16LEN.txt | UTF-16LE | 無し | |||||||
Test_UTF16LEB.txt | UTF-16LE | 付き | |||||||
Test_UTF16BEN.txt | UTF-16BE | 無し | |||||||
Test_UTF16BEB.txt | UTF-16BE | 付き | |||||||
Test_XML.xml | UTF-8 | 無し |
下記内容のXMLファイル。コードは図29
| ||||||
Test_HTML.php | UTF-8 | 無し | 1~2行目:GET(g1=, g2=)で送った文字列 3~4行目:POST(p1=, p2=)で送った文字列 |
2.XMLHTTPのプロパティ
プロパティは9種ありますが、以下の様に生成するオブジェクトの種類により使えるものが制限されます。表の内容としては図09・図12と同じですが、再掲します。
プロパティ | 事前バインディング | 実行時バインディング | |||||
---|---|---|---|---|---|---|---|
MSXML2 | Win | MSXML2 | Micro | Win | |||
Server | XML | Win | Server | XML | XML | Win | |
readyState | 〇 | 〇 | 〇 | 〇 | 〇 | ||
onReady | 〇 | 〇 | 〇 | 〇 | 〇 | ||
status | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 |
statusText | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 |
response | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 |
response | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 |
response | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 |
response | 〇 | 〇 | 〇 | 〇 | 〇 | ||
option | 〇 | 〇 |
上記プロパティの内、一番下の「Option」は引数に0~19の値を指定することで様々な値を取得/設定できるプロパティです。引数値により取得/設定が異なりますので、詳細は図33を参照下さい。
また上から2番目の「onReadyStateChange」は、readyState値が変化した時にイベントとして動くもののようです(VBAでは動作が確認できず)。onReadyStateChangeはプロパティの1つに分類されているため、図16の表内に入れています。
その他のプロパティはVBAでは全て取得専用で、設定はできません。
2-1.readyState
XMLHTTPでのリクエストは同期・非同期の両方に対応しています。同期とは「Sendメソッドでリクエストを送信した後、サーバーからレスポンスが戻ってくるまで次のコード行に制御が移動しない」ことを指し、非同期では「Sendメソッドでリクエストを送信したら、すぐに次の行に制御が移動」します。
しかし同期で実行すると、通信状態や取得するファイルのサイズにもよりますが、プログラムが進まないためにフリーズし、ユーザー操作不可の状態となる可能性があります。ですので通常は「非同期」でリクエストするようですが、その際には「レスポンスが完了してから次の工程に進む」必要が出てきます。この状態把握にreadyStateプロパティが使われます。
readyStateプロパティは、下記の様に現在の状態を表します。状態は0から4に向かって進みますが、Do~Loopで状態を調べた時には「中間の状態を取得出来ない」場合もあります。例えば図18では「状態1の後に、すぐ状態4が現れる」という現象になる可能性がありますので「不等号を使って状態を感知」するか、または「最終状態(=操作完了)か否かを感知」する方法が良さそうです。
定数 | 値 | 状態 |
---|---|---|
Unsent | 0 | XMLHTTPオブジェクトは作成済み |
Opened | 1 | Openメソッドの呼び出し済み |
Headers_Received | 2 | Sendメソッドが呼び出し済み+レスポンスヘッダを受信済み |
Loading | 3 | レスポンスボディを受信中 |
Done | 4 | 操作完了 |
以下のサンプルコードではDo~Loopを使って状態4(操作完了)になるまで待ち、状態4になったら抜け出し次に移っています。
- '========== ⇩(3) readyStateでレスポンスが完了するまで待つ ============
- Sub test001()
- Dim XHR As Object
- Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF8N.txt" '←UTF-8ファイル
- Set XHR = CreateObject("MSXML2.XMLHTTP.6.0")
- With XHR
- .Open "GET", FN, True
- .send
- Do Until .readyState = 4 '←レスポンス完了まで待つ
- DoEvents: DoEvents
- Loop
- If Not .Status = 200 Then Exit Sub '←正常処理以外は終了させる
- MsgBox .responseText
- End With
- Set XHR = Nothing
- End Sub
45行目「Set XHR = CreateObject("MSXML2.XMLHTTP.6.0")」で、XMLHTTPオブジェクトを生成しています。ここではServer系では無いオブジェクトを使っていますが、図18内のコードを実行する上ではServer系でもOKです(但し WinHttpRequest.5.1 を使うと、51行目のreadyStateプロパティが無いので異なる処理が必要です)。
48行目「.Open "GET", FN, True」では、アクセスするサーバーのURLを指定(第2引数)し、非同期モード(第3引数)でリクエストの準備をしています。
49行目「.send」では、リクエストをサーバーに送信しています。非同期モードですので、リクエスト送信後すぐに次の行を実行します。
51~53行目のDo~Loopでは、Loopの終了条件を「.readyState = 4」としています。つまり「レスポンスが完了(readyState = 4)」するまではDo~Loopを回すことになります。レスポンス完了したら制御は54行目に移動します。
54行目「If Not .Status = 200 Then Exit Sub」は、下で説明するStateプロパティ値が200(=正常処理)以外は異常と見なしてプログラムを終了させています。
56行目「MsgBox .responseText」では、responseTextプロパティに格納されたテキストをメッセージとして表示しています。
2-2.onReadyStateChange
onReadyStateChangeプロパティは「readyStateプロパティ値が変化する時にイベントを発生し、指定した関数を実行する」と説明されています。しかし色々と試してみましたが、イベントによる関数実行は確認できませんでした。MSXML2系オブジェクトを使ってプロパティ設定をする際には「エラーは出ない」為、onReadyStateChangeプロパティ自体は存在するようです。ですので私の設定方法が間違っているのか、またはVBAではイベントを発生する機能を中止しているのかもしれません。
2-3.status 及び statusText
statusプロパティとstatusTextプロパティは、通信を行った結果を表す値(HTTPステータスコード)とその説明文です。このプロパティ値はレスポンスが返ってきた後でないとエラーとなります。サーバー側と正常にやり取りが出来れば、通常は「Status=200(statusText="OK")」となります。しかしstatus 及び statusTextには、その他の値が返ってくる場合があります。レスポンスは以下の5つのクラスに分類されます。
・情報レスポンス (100番台) ・・・正常扱い
・成功レスポンス (200番台) ・・・正常扱い
・リダイレクトメッセージ (300番台) ・・・正常扱い
・クライアントエラーレスポンス (400番台) ・・・エラー扱い
・サーバーエラーレスポンス (500番台) ・・・エラー扱い
各クラスの詳細status番号(HTTPステータスコード)およびstatusTextの文字列・内容は以下となります。
クラス | status | statusText | 内容 |
---|---|---|---|
情報 | 100 | Continue | リクエスト継続可能 |
101 | Switching Protocols | プロトコルを切り替え | |
102 | Processing | 処理中で、まだレスポンスを提供できない | |
103 | Early Hints | リソースの事前読み込み可 | |
成功 | 200 | OK | リクエスト成功し、正常処理 |
201 | Created | リクエスト成功し、新たなリソースを作成 | |
202 | Accepted | リクエスト受理したが、処理未 | |
203 | Non-Authoritative Information | レスポンス情報が複製データ | |
204 | No Content | リクエストに対するコンテンツ無し。但しヘッダは有用。 | |
205 | Reset Content | リクエストを送信した文章のリセットを指示 | |
206 | Partial Content | 要求の内、一部分のみのリクエストが成功 | |
リダイレクト | 300 | Multiple Choice | リクエストに対して複数のレスポンス有り |
301 | Moved Permanently | 恒久的に移動 | |
302 | Found | 一時的に移動 | |
304 | Not Modified | 更新されていない(ブラウザキャッシュ使用) | |
クライアントエラ| | 400 | Bad Request | 一般的なクライアントエラー |
401 | Unauthorized | アクセス権が無い、または認証に失敗 | |
402 | Payment Required | 料金の支払いをするまでリクエストの処理不可 | |
403 | Forbidden | 閲覧権限が無いファイルやフォルダ | |
404 | Not Found | Webページが見つからない | |
405 | Method Not Allowed | 送信するクライアント側のメソッドが許可されていない | |
406 | Not Acceptable | サーバ側が受付不可能な値 | |
407 | Proxy Authentication Required | プロキシサーバの認証情報が不足 | |
408 | Request Timeout | リクエスト送信後のやり取り時間が長く時間切れ | |
409 | Conflict | サーバに既に存在しているデータが競合している | |
410 | Gone | ファイルが削除されWebページが存在しない | |
411 | Length Required | Content-Lengthヘッダが無い | |
412 | Precondition Failed | ヘッダで定義された前提条件が満たされていない | |
413 | Payload Too Large | アップロードしたファイルの容量が上限を超えた | |
414 | URI Too Long | 指定したURLが長すぎる | |
415 | Unsupported Media Type | サーバで許可していないリクエストの種類 | |
416 | Range Not Satisfiable | サーバーがリクエストされた容量を提供できない | |
417 | Expectation Failed | サーバが拡張されたステータスコードを返せない | |
422 | Unprocessable Entity | リクエストは適正だが意味が異なる | |
423 | Locked | リクエスト内容がロックされている | |
425 | Too Early | サーバが繰り返し処理が発生される可能性あり(≒無限ループ) | |
426 | Upgrade Required | HTTP/1.1にアップグレードが必要 | |
429 | Too Many Requests | 一定時間内にリクエスト数が多すぎる | |
431 | Request Header Fields Too Large | リクエストヘッダーが長すぎる | |
サ|バ|エラ| | 500 | Internal Server Error | 何らかのサーバ内で起きたエラー |
501 | Not Implemented | サーバーがリクエストに満たすのに必要な機能をサポートしていない | |
502 | Bad Gateway | ゲートウェイ・プロキシサーバが不正なリクエストを受け取り拒否 | |
503 | Service Unavailable | 一時的にサーバにアクセス出来ず | |
504 | Gateway Timeout | サーバからレスポンスがなくタイムアウト | |
505 | HTTP Version Not Supported | HTTPバージョンがサーバによってサポートされていない | |
506 | Variant Also Negotiates | URLを返すコンテンツで配置ミスなどによる内部サーバエラー | |
507 | Insufficient Storage | サーバで処理するためのストレージ容量不足 | |
508 | Loop Detected | 無限ループによりサーバーが操作終了 | |
510 | Not Extended | アクセス集中によるエラー | |
511 | Network Authentication Required | ネットワーク認証要 |
図19
上記のように100番台~300番台は正常、400番台~500番台はエラーですので、正常以外の時に処理を終わらすには「If XMLHttp.Status >= 400 Then Exit Sub」等とすれば良いことになります。
しかし表内には「これは正常と言えるのか?」というような内容も含まれているため、今回のサンプルコードでは図18の54行目「If Not .Status = 200 Then Exit Sub」のように、「Status=200」のみを正常として処理しています。
2-4.responseText
responseTextプロパティには、取得したテキストデータが入ります。そのresponseText値を使い、テキストファイルの内容を取得する事ができます。以下がコード例です。- '========== ⇩(4) responseTextでテキストデータを取得 ============
- Sub test002()
- Dim XHR As Object
' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_SJIS.txt"' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF8N.txt"' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF8B.txt"' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16LEN.txt"- Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16LEB.txt" '←UTF-16LE(BOM付)ファイル
' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16BEN.txt"' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16BEB.txt"- Set XHR = CreateObject("MSXML2.ServerXMLHTTP.6.0")
- With XHR
- .Open "GET", FN, True
- .send
- Do Until .readyState = 4
- DoEvents: DoEvents
- Loop
- If Not .Status = 200 Then Exit Sub
- MsgBox .responseText
- End With
- Set XHR = Nothing
- End Sub
84行目「.Open "GET", FN, True」でリクエストの準備を行い、85行目「.send」でリクエストを送信し、87~89行目のDo~Loopでレスポンスが届くのを待ちます。受け取ったレスポンス内のテキストデータをresponseTextプロパティを通して取得し、出力しているのが92行目「MsgBox .responseText」です。
アクセスしている先は73~79行目で、今回は全7種の文字コードの固定テキストファイルを準備しました(図15参照)。その文字コード別ファイルを使っての出力結果が以下です。
赤字で示した文字コードのテキストは正しく取得できるのですが、それ以外は正しく取得できない事がわかります。

図21
また図20で使用したオブジェクトは81行目「Set XHR = CreateObject("MSXML2.ServerXMLHTTP.6.0")」のようにServerXMLHTTPですが、それ以外にも図08・図11のように多くのオブジェクトが使用できます。
この「生成オブジェクト × 文字コードファイル」で、正しいテキストデータが取得できるかを整理したのが以下になります。
なお表中の「事前」は事前バインディング、「実行時」は実行時バインディングで使用するオブジェクトを表しています。
生成オブジェクト | S-JIS | UTF-8 | UTF-16LE | UTF-16BE | |||||
BOM無 | BOM付 | BOM無 | BOM付 | BOM無 | BOM付 | ||||
事 前 | MSXML2 | Server | × | 〇 | 〇 | × | 〇 | × | 〇 |
XMLHTTP | × | 〇 | 〇 | × | 〇 | × | 〇 | ||
WinHttp | WinHttp | × | × | × | × | × | × | × | |
実 行 時 | MSXML2 | Server | × | 〇 | 〇 | × | 〇 | × | 〇 |
XMLHTTP | × | 〇 | 〇 | × | 〇 | × | 〇 | ||
Microsoft | XMLHTTP | × | 〇 | 〇 | × | 〇 | × | 〇 | |
WinHttp | WinHttp | × | × | × | × | × | × | × |
まとめるとresponseTextプロパティで取得できる文字コードには制限があり、UTF-8 または UTF-16のBOM付で、且つWinHttp系以外のオブジェクトであれば、正しくデータが取得できるようです。
なお WinHttp系は、ASCII(英数字のみ)であれば問題なく取得できますが、半角カナ・漢字など日本語を含む文字コードには対応していないようです。もしWinHttp系のオブジェクトを使用する場合は、下で説明するresponseBodyプロパティを通してテキスト内容を取得する必要があります。
2-5.responseBody
responseBodyプロパティには、Web上のテキストデータの文字コードが「バイナリ値として配列の形」で入ります。配列のインデックスはゼロ始まりです。BOMが付いている場合はBOMもバイナリ値として入ってきます。上で説明したresponseTextで文字化けしてしまう場合には、responseBodyプロパティを使用し文字コードに合った変換をする事で、テキストデータを得ることができます。
まず、バイナリデータを「String型に変換」して表示するサンプルコードが以下になります。
- '========== ⇩(5) UTF16LEのデータをresponseBodyで取得 ============
- Sub test003()
- Dim XHR As Object
' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_SJIS.txt"' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF8N.txt"' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF8B.txt"- ' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16LEN.txt" '←UTF-16LE(BON無)ファイル
Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16LEB.txt"' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16BEN.txt"' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16BEB.txt"- Dim Str As String
- Set XHR = CreateObject("MSXML2.serverXMLHTTP.6.0")
- With XHR
- .Open "GET", FN, True
- .send
- Do Until .readyState = 4
- DoEvents: DoEvents
- Loop
- If Not .Status = 200 Then Exit Sub
- Str = .responseBody
- MsgBox Str
- End With
- Set XHR = Nothing
- End Sub
120行目「Dim Str As String」でString型の変数を準備し、133行目「Str = .responseBody」でresponseBodyプロパティの配列データをString型に変換しています。その変換後の文字列を134行目「MsgBox Str」で出力しています。MsgBoxの引数はString型なので、133~134行目を1つにまとめて「MsgBox .responseBody」としてもOKです。
図20と同様に、7種の文字コードのテキストファイル(113~119行目)を出力した結果が以下です。

図24
バイナリデータが入った配列をString型に変換して正しいテキストデータが得られるのは「UTF-16LE」のみです。これはVBAのString型がUnicode(=UTF-16LE)で作られているためです。
但し「BOM有りのUTF-16LE」の場合には「先頭のBOM(2バイト分)が、"?"印に文字化け」しますので、変換後に先頭1文字を削除する必要があります。
上で紹介した responseTextプロパティ、responseBody+String型変換を使った手法では、Shift-JISやUTF-16BEの文字コードファイルは文字化けします。この文字化けは残念ながらXMLHTTPのみでは対応が出来ないため、以下のようにADODB.Streamの力を借りてテキストに変換します。なおADODB.Streamについては「ADODB.Stream編」を参照下さい。
- '========== ⇩(6) UTF-16BEのデータをresponseBodyで取得 ============
- Sub test004()
- Dim XHR As Object
- Dim ADOst As Object
' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_SJIS.txt"' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF8N.txt"' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF8B.txt"' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16LEN.txt"' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16LEB.txt"- Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16BEN.txt" '←UTF-16BEファイル
' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16BEB.txt"- Dim Str As String
- Set XHR = CreateObject("MSXML2.serverXMLHTTP.6.0")
- With XHR
- .Open "GET", FN, True
- .send
- Do Until .readyState = 4
- DoEvents: DoEvents
- Loop
- If Not .Status = 200 Then Exit Sub
- Set ADOst = CreateObject("ADODB.Stream") '←ADODB.Streamオブジェクトの生成
- ADOst.Open '←Streamを開く
- ADOst.type = 1 '←Streamをバイナリ型にする
- ADOst.write .responseBody '←Streamにレスポンスの配列データを入れる
- ADOst.Position = 0 '←PositionをStreamの先頭に移動
- ADOst.type = 2 '←Streamをテキスト型に変更
' ADOst.Charset = "Shift-JIS"' ADOst.Charset = "UTF-8"' ADOst.Charset = "unicode"- ADOst.Charset = "UTF-16BE" '←Streamの文字コードをUTF-16BEにする
- Str = ADOst.ReadText(-1) '←Streamから全テキストデータを読み取る
- ADOst.Close
- Set ADOst = Nothing
- MsgBox Str
- End With
- Set XHR = Nothing
- End Sub
166行目「.Open "GET", FN, True」でリクエスト準備をし、167行目「.send」でリクエストを送信します。169~171行目のDo~Loopでレスポンスが返ってくるのを待ち、172行目「If Not .Status = 200 Then Exit Sub」で正常(Status = 200)以外の時は終了させます。ここまでは今までと同じです。
174行目「Set ADOst = CreateObject("ADODB.Stream")」でADODB.Streamオブジェクトを生成し、175行目「ADOst.Open」でStreamを開きます。
177行目「ADOst.write .responseBody」では、サーバーからレスポンスで返ってきた「テキストのバイナリデータの配列」をバイトデータとしてStreamに書き込んでいます。その書き込むデータ型に合わせるため176行目「ADOst.type = 1」でStreamをバイナリ型にしています。
この時点でStreamはバイナリ型ですが、このStreamをテキスト型に変更すれば「Stream内のバイナリデータはテキストデータに変換」されるのですが、型を変換するにはデータ読み書き位置(Positon)が先頭にある必要がありますので、179行目「ADOst.Position = 0」でStreamの先頭に移動させています。
Positionが先頭になったら180行目「ADOst.type = 2」でStreamをテキスト型に変更させています。またテキストの文字コードを指定しておく必要があるため、184行目「ADOst.Charset = "UTF-16BE"」でStreamの文字コードをUTF-16BEに変更しています。
ここまでの処理で、Stream内のレスポンスデータはUTF-16BEのテキストデータになりますので、185行目「Str = ADOst.ReadText(-1)」で全テキストデータを取り出し、189行目「MsgBox Str」で出力しています。
なお図25では、159行目のUTF-16BEのテキストファイルを呼び出したので、Streamを同じUTF-16BEの文字コードに設定(184行目)しましたが、その他(154~160行目)の文字コードのテキストファイルを呼び出す際には、181~184行目の中の「文字コードに対応した指定値をCharsetプロパティに設定」すれば、以下のようにどの文字コードの場合にも正しく出力されます。

図26
なお、文字コードに対応しているCharset値は以下のようになりますが、詳細はADODB.Stream編の「Charsetの設定と文字コードとの関係表」を参照下さい。
Charset= | Shift-JIS | UTF-8 | UTF-16LE | UTF-16BE | |||
---|---|---|---|---|---|---|---|
BOM無 | BOM付 | BOM無 | BOM付 | BOM無 | BOM付 | ||
Shift-JIS | 〇 | ||||||
UTF-8 | 〇 | 〇 | |||||
unicode(既定) | 〇 | 〇 | 〇 | ||||
UTF-16BE | 〇 | △ |
図27
なおShift-JISの場合には、ADODB.Streamでは無くVBAのStrConv関数を使って、以下のようなコードとしてもOKです。
- '========== ⇩(7) Shift-JISのデータをresponseBodyで取得 ============
- Sub test005()
- Dim XHR As Object
- Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_SJIS.txt"
- Dim Str As String
- Set XHR = CreateObject("MSXML2.serverXMLHTTP.6.0")
- With XHR
- .Open "GET", FN, True
- .send
- Do Until .readyState = 4
- DoEvents: DoEvents
- Loop
- If Not .Status = 200 Then Exit Sub
- Str = StrConv(.responseBody, vbUnicode)
- MsgBox Str
- End With
- Set XHR = Nothing
- End Sub
227行目「Str = StrConv(.responseBody, vbUnicode)」では、Shift-JISのテキストのバイナリデータをStrConv関数でUnicode(String型のUTF-16LE)に変換しています。
![]() 図28の227行目でStrConv関数の第2引数に指定した"vbUnicode"は「システム既定の文字コードをUnicodeに変換」するというものです。ここで言う「システム」はWindowsでは無くExcelのようです。 Excelのシステム既定の文字コードの確認方法は、セル上に全角文字が記入してあるExcelのファイルを「テキスト(タブ区切り)(*.txt)」で保存し、メモ帳などで開いた時に表示される文字コードで確認できるようです。この手法でメモ帳を開くと、右下にはANSIと表示されるのでShift-JISと分かります。 文字コードの確認方法として本当にこの手法が正しいのかは分かりませんが、Windows10や11の文字コードはUnicode(UTF-16LE)のはずなので、StrConv(.responseBody, vbUnicode)での変換結果を見ても「Excelの文字コードはShift-JIS」と言えるようです。 |
2-6.responseStream
Microsoftのサイトを見ると、responseStreamプロパティはテキストを「IStream」として取得する とあります。しかしVBAにはIStream型というものが無く、直接扱うことはできません。そこで色々調べたり試してみたのですが、結論としては「VBAでは簡単にはresponseStreamの値を取り出せない」ことが分かりました。
VBAとして取得したデータを扱うには「responseBody」や「responseText」を使用するしか無さそうです。
2-7.responseXML
responseXMLプロパティにはXMLデータが入り、そのデータ型は「DomDocumentオブジェクト型」となります。ですのでExcelが文字列処理できるデータを取得するには、DomDocumentオブジェクト型のTextプロパティやXMLプロパティ値を使うことになります。まず今回使用するXMLファイル(図15の Test_XML.xml)のコードを下記に示します。みかんとりんごの二次元の価格表です。
- '========== ⇩(8) XMLファイルの内容 ============
- <Data>
- <果実>
- <種類>みかん</種類>
- <価格>130</価格>
- </果実>
- <果実>
- <種類>りんご</種類>
- <価格>250</価格>
- </果実>
- </Data>
このXMLファイルを読み取り、出力するのが以下のコードです。
- '========== ⇩(9) XMLファイルを読み取る ============
- Sub test006()
- Dim XHR As Object
- Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_xml.xml"
- Set XHR = CreateObject("MSXML2.XMLHTTP.6.0")
- With XHR
- .Open "GET", FN, True
- .send
- Do Until .readyState = 4
- DoEvents: DoEvents
- Loop
- If Not .Status = 200 Then Exit Sub
- MsgBox .responseXML.Text
- End With
- Set XHR = Nothing
- End Sub
responseXMLプロパティはDOMDocumentオブジェクト型です。その下のTextプロパティにはテキストとしてデータが入っているので、266行「MsgBox .responseXML.Text」で取得し表示させています。メッセージ出力の様子は以下の様になります。

図31
データである「みかん」と「130」の間には「SP(半角スペース)」が入った形ですが、これは図29の「<種類>みかん</種類>」と「<価格>130</価格>」の間に改行が入ったXMLファイルだからです。
もし「<種類>みかん</種類><価格>130</価格>」というように1行でデータセットが書かれていれば、「みかん」と「130」の間にはスペースが入らず連続したデータとして出力されますし、逆にタグとデータが下記のように行を変えて書かれていれば、SP(半角スペース)の両側にLf(改行)マークが入るようです。
- '========== ⇩(10) XMLファイルの内容2 ============
- <Data>
- <果実>
- <種類>
- みかん
- </種類>
- <価格>
- 130
- </価格>
- :
- :
XMLファイルの書き方で処理方法が変わってしまうのは、VBAとしてはちょっとやっかいです。一方、ワークシートから上部リボンの「データ」タブ→「データの取得と変換」グループを使用すれば、図31の一番右側のように表形式でデータ取得ができます。XMLデータの場合は、この機能を活用した方が良いかもしれません。
なおタグ名が分かっていれば、XMLHTTP以外の方法でもデータを取り出す事が可能ですが、ここでは省略します。
2-8.option
optionプロパティは、各種情報の取得/設定をします。構文は以下で、オブジェクトとしてWinHttp.WinHttpRequest使用時のみ使えます。WinHttpRequest.option(Option) As Variant
引数(Option)に指定する値は、以下のWinHttpRequestOption列挙型から選択します。
定数 | 値 | 取得/設定 | 内容 | 取得/設定の例 |
---|---|---|---|---|
WinHttpRequestOption_ UserAgentString | 0 | 取得/設定 | ユーザ-エージェント(サーバーに要求を出すクライアントアプリ)の名前 | "Mozilla/4.0" |
WinHttpRequestOption_ URL | 1 | 取得のみ | URL値(リダイレクトした場合はリダイレクト先のURL) | "http://www.・・・" |
WinHttpRequestOption_ URLCodePage | 2 | 取得/設定 | URLの文字コード | 65001 (=UTF-8:既定) |
WinHttpRequestOption_ EscapePercentInURL | 3 | 取得/設定 | URL文字内の%文字がエスケープされるか否か | True="%25"にエスケープ False="%"のまま(VBAの既定) |
WinHttpRequestOption_ SslErrorIgnoreFlags | 4 | 取得/設定 | どのサーバー証明書エラーを無視するか(図34参照) | 既定=0 |
WinHttpRequestOption_ SelectCertificate | 5 | 設定のみ | 認証の為にサーバーに送信するクライアント証明書の場所 | ? |
WinHttpRequestOption_ EnableRedirects | 6 | 取得/設定 | 自動的にリダイレクトされるか否か | True=リダイレクトされる(既定) |
WinHttpRequestOption_ UrlEscapeDisable | 7 | 取得/設定 | URLパス及びクエリの不安全な文字をエスケープ変換するか否か | False=エスケープする(既定) True=そのまま |
WinHttpRequestOption_ UrlEscapeDisableQuery | 8 | 取得/設定 | クエリ内の不安全な文字をエスケープ変換するか否か | False=エスケープする True=そのまま(既定) |
WinHttpRequestOption_ SecureProtocols | 9 | 設定のみ | セキュリティプロトコル(図36参照) | 既定=0x0028(未確認) |
WinHttpRequestOption_ EnableTracing | 10 | 取得/設定 | ネットワークトラフィック監視の為のトレースが有効か否か | 既定=False? |
WinHttpRequestOption_ RevertImpersonation | 11 | 取得/設定 | 証明書認証操作の間、クライアントの偽装(承認状態)を一時的に元に戻すか否か | True=一時的に元に戻す(既定) |
WinHttpRequestOption_ EnableHttps | 12 | 取得/設定 | HTTPSから HTTPへのリダイレクトを有効にする | True=有効にする False=無効(既定) (HTTPS→HTTP以外のリダイレクト有効) |
WinHttpRequestOption_ EnablePassport | 13 | 取得/設定 | Passport認証のサポートを有効化 | False=無効(既定) |
WinHttpRequestOption_ MaxAutomaticRedirects | 14 | 取得/設定 | リダイレクトの最大数 | 既定=10 |
WinHttpRequestOption_ MaxResponseHeaderSize | 15 | 取得/設定 | 応答ヘッダー部分の最大サイズ(バイト単位で取得/設定) | 既定=65536 (64KB) |
WinHttpRequestOption_ MaxResponseDrainSize | 16 | 取得/設定 | 再接続の為にレスポンスから排出されるデータ量?(バイト単位で取得/設定) | 既定=1024000 (1MB) |
WinHttpRequestOption_ EnableHttp1_1 | 17 | 取得/設定 | HTTP/1.1を使用するか(=HTTP/1.0を使用しないか) | True=HTTP/1.1を使用(既定) |
WinHttpRequestOption_ EnableCertificate | 18 | 取得/設定 | 証明書失効チェックの有効化 | Falseが既定? |
WinHttpRequestOption_ RejectUserpwd | 19 | 取得/設定 | パスワードを拒否? | Falseが既定? |
WinHttpRequestOption_URLCodePage(値=2)は、Openメソッドに指定するURLの文字コードを指定します。この機能は「setOption」の第一引数にSXH_OPTION_URL_CODEPAGE(値=0)を指定した場合と同じと思われるので、設定値/取得値も図58と同じと思われます。VBAの文字コードはUTF-8では無いと思うのですが、既定またはUTF-8(値=65001)以外を指定するとURLの半角カナや全角文字は文字化けしてサーバー側に伝わります。
このURLがUTF-8というのは、サーバー(atsumitm.iobb.net)のO/Sの文字コードがUTF-8に設定されている為かもしれません。そうだとすれば、サーバー毎に文字コード設定が必要という事になり、かなりやっかいな問題です。
WinHttpRequestOption_EscapePercentInURL(値=3)は、URLの文字内に「%文字」が存在した場合に「"%"文字のまま(False)」とするか「"%25"にエスケープ(True)」するかを取得/設定するものです。この機能は「setOption」の第一引数にSXH_OPTION_ESCAPE_PERCENT_IN_URL(値=1)を指定した場合と同じと思われます。
なお他の言語ではTrueが既定値のようですが、VBAで試してみるとFalseが既定のようです。
WinHttpRequestOption_SslErrorIgnoreFlags(値=4)は、証明書関連のエラーマスクです。取得/設定値は以下の内容で、設定時は「無視したいエラー内容」の値を指定(加算可)します。0x3300(10進数で 13056)を指定すると全ての証明書エラーを無視することになるようです。
値 (カッコ内は10進数) | エラー内容 |
---|---|
0x0100(256) | 不明な証明機関(CA)または信頼されていないルート |
0x0200(512) | 間違った使用法 |
0x1000(4096) | 共通名(CN)が無効 |
0x2000(8192) | 無効な日付または有効期限切れ |
この機能は「setOption」の第一引数にSXH_OPTION_IGNORE_SERVER_SSL_CERT_ERROR_FLAGS(値=2)を指定した場合と同じと思われます。設定値/取得値は図59と同じと思われますが、定数は設定されていないようです。なお、setOptionとは異なり「既定値はゼロ」のようなので、そのままでは証明書関連で出るエラーは全て引っかかる事になるようです。
WinHttpRequestOption_SelectCertificate(値=5)は、クライアント証明書を設定するもののようです。「setOption」の第一引数にSXH_OPTION_SELECT_CLIENT_SSL_CERT(値=3)を指定した場合と同じと思われますが、setOptionと同様に良く分かりませんでした。
WinHttpRequestOption_UrlEscapeDisable(値=7)は、URL内の全ての「不安全な文字」をエスケープする機能です。不安全な文字とは「#(%23) ¥(%5c) ^(%5e) [(%5b) ](%5d) {(%7b) }(%7d) |(%7c)」などを指し、False指定によりエスケープ変換(カッコ内)されます。
ざっと試したところ「& = ? % / ~」は対象外のようです。
なおこの設定は、URLのパス部(ドメイン以下ファイル名まで)およびクエリ部(?印以降のファイルに渡すデータ部)に対して影響します。
WinHttpRequestOption_UrlEscapeDisableQuery(値=8)は、URL内の?印以降の「ファイルに渡すクエリ部」の不安全な文字をエスケープする機能です。値=7と類似していますが、こちらは?印以降のみが対象範囲です。
ですので「値=7と値=8を組み合わせ」ることで、パス側・クエリ側のエスケープする・しないを以下のように制御することが可能です。
パス側 | |||
---|---|---|---|
エスケープ | そのまま | ||
ク エ リ 側 | エスケープ | Option(7)=False(既定) Option(8)=False | Option(7)=True Option(8)=False |
そのまま | Option(7)=False(既定) Option(8)=True(既定) | Option(7)=True Option(8)=True(既定) |
WinHttpRequestOption_SecureProtocols(値=9)は、セキュリティプロトコルの指定です。値は以下の内容との事です。
値 (カッコ内は10進数) | プロトコル |
---|---|
0x0008(8) | SSL 2.0 |
0x0020(32) | SSL 3.0 |
0x0080(128) | TLS 1.0 |
Microsoftの説明では取得/設定が可能との事ですが、VBAで値取得するとエラーが発生します。つまりVBAでは設定のみのようです。取得不可のため、既定だと紹介されている値(0x0028:SSL2.0またはSSL3.0)も確認できません。
またゼロを指定すると「受け入れ可能なセキュリティプロトコルが決定できずエラーが発生」と他サイトでは説明していますが、VBAでゼロを設定しても特にエラーが出ることはありません。
値=10以降の内容は良く分かりませんし、他サイトでの情報もほとんどありませんので割愛します。
下記コードはOptionプロパティの全ての値(値=5と値=9は設定のみのため除外)を取得するものです。
- '========== ⇩(11) Optionプロパティで設定情報を取得 ============
- Sub test007()
- Dim XHR As Object
- Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16LEB.txt"
- Dim Str As String
- Dim i As Integer
- Set XHR = CreateObject("Winhttp.winhttprequest.5.1")
- With XHR
- .Open "GET", FN, False
- .send
- If Not .Status = 200 Then Exit Sub
- For i = 0 To 19
- If Not (i = 5 Or i = 9) Then
- Str = Str & i & vbTab & .Option(i) & vbCrLf
- End If
- Next i
- MsgBox Str
- End With
- Set XHR = Nothing
- End Sub
Optionプロパティは「Winhttp.winhttprequestオブジェクト」のみで使用できますので、オブジェクト生成は287行目「Set XHR = CreateObject("Winhttp.winhttprequest.5.1")」としています。
そしてWinhttp.winhttprequestオブジェクトにはreadyStateプロパティがありませんので、ここでは290行目「.Open "GET", FN, False」と同期モードでOpenしています。
295~299行目のFor~Nextでは、値=0~19のOptionプロパティ値を文字列にしています。但し、値=5と値=9は設定のみなので除外する必要があるので、296行目「If Not (i = 5 Or i = 9) Then」で文字列化の条件を追加しています。
出力された様子は以下です。

図38
3.XMLHTTPのメソッド
メソッドは15種ありますが、生成するオブジェクトの種類により使えるメソッドが決まっています。図09・図12と内容が重複します。メソッド | 事前バインディング | 実行時バインディング | 実行 位置 | ||||||
---|---|---|---|---|---|---|---|---|---|
MSXML2 | Win | MSXML2 | Micro | Win | |||||
Server | XML | Win | Server | XML | XML | Win | |||
実行 | |||||||||
open | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 | ー | |
send | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 | ー | |
abort | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 | bc | |
設定 | |||||||||
set | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 | b | |
waitFor | 〇 | 〇 | 〇 | 〇 | c | ||||
set | 〇 | 〇 | 〇 | 〇 | a | ||||
setProxy | 〇 | 〇 | 〇 | 〇 | b | ||||
setOption | 〇 | 〇 | a | ||||||
setProxy | 〇 | 〇 | b | ||||||
setClient | 〇 | 〇 | b | ||||||
set | 〇 | 〇 | b | ||||||
set | 〇 | 〇 | b | ||||||
取得 | |||||||||
getAll | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 | c | |
get | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 | 〇 | c | |
getOption | 〇 | 〇 | (a)bc |
15種のメソッドの内、メインは「Open」と「Send」ですが、その他のメソッドは以下のように「(a)Openの前」「(b)Openの後で且つSendの前」「(c)Sendの後」のどこで実行するかが決まっています。上表の右端列の"a・b・c"は、各メソッドを実行する位置を表しています。
- '========== ⇩(12) メソッドの実行位置 ============
- (a)
- Open ・・・
- (b)
- Send ・・・
- (c)
なお図39の一番下のgetOptionの引数に-1を指定した時はURLが戻されるのですが、Open前に実行するとその時点ではURLは指定されていないためエラーとなります。そのためOpen前の "a" はカッコ付きとしています。
3-1.open
openメソッドでは、通信の方法や送信先のURLを指定します。構文は以下です。XMLHTTP.open(bstrMethod, bstrUrl ,[varAsync], [bstrUser], [bstrPassword])
5つある引数の内容は以下になります。
引数 | 型 | 内容 | ||
---|---|---|---|---|
1 | bstrMethod | 必須 | String | 通信方法(リクエストタイプ) |
2 | bstrUrl | 必須 | String | リクエストの送信先となるURL |
3 | varAsync | 省略可 | Boolean | True=非同期 False=同期(既定) |
4 | bstrUser | 省略可 | String | 認証プロセスで使用するユーザー名 既定は""(長さゼロ文字列) |
5 | bstrPassword | 省略可 | String | 認証プロセスで使用するパスワード 既定は""(長さゼロ文字列) |
第1引数(bstrMethod)には、通信方法(リクエストタイプ)を指定します。通信方法には、以下のように多くの種類があります。表の右列には、各通信方法でリクエストした時にファイル内容を取得できるか否かを示しています。
なお表内の「リソース」とは、クライアントが「サーバー側から受け取るデータ」と考えて下さい。
第一引数 (接続方法) | 内容 | サーバー上のファイル | ||
---|---|---|---|---|
固定テキスト | 変動テキスト(PHP等) | |||
GET法 | POST法 | |||
GET | リソースをリクエストする | 〇 | 〇 | × |
POST | リソースに必要なデータを送信する | 〇 | 〇 | 〇 |
HEAD | ヘッダ情報のみをリクエストする | 空データ | 空データ | 空データ |
PUT | リソースを全て変更 | 405エラー | 〇 | × |
PATCH | リソースを部分的に変更 | 405エラー | 〇 | × |
DELETE | 指定したリソースを削除 | 405エラー | 〇 | × |
CONNECT | サーバーとの間にトンネルを確立 | Send実行時にエラー | ||
OPTIONS | リソースの通信オプションを示す | 空データ | 〇 | × |
TRACE | リクエストをオウム返しに返す | 405エラー | 405エラー | 405エラー |
LINK | URLとリソースを結合する | 501エラー | 〇 | × |
UNLINK | LINKを解除する | 501エラー | 〇 | × |
図42
表からも分かるように、VBAで固定テキストファイルの内容を取得できるのは「GET」および「POST」の2種ですが、通常は「GET」を使用するのが一般的なようです。
また、表の右側2列(「変動テキスト(PHP等)」の列)は「クライアント側からデータを渡し、そのデータをサーバー側が加工してからクライアントに返す」場合の接続方法ごとの結果を示しました。
クライアント側のデータを渡す方法としては「GET法(URLの後ろにデータを添付)」「POST法(ボディーにデータを添付)」の2つがあり、上表ではGET法が色々な接続方法に対応しているようにも見えます。しかし基本的には以下のように、データ添付方法=接続方法とすべきです。
・固定ファイルを取得する場合= 「GET」を指定 ・クライアントからデータを送る場合= GET法(URLに添付)は「GET」、POST法(ボディに添付)は「POST」を指定 (詳細は「クライアント側からデータをサーバーに送付」を参照) |
第2引数(bstrUrl)は、リクエストの送信先となるURL(≒テキストデータが存在する場所)を指定します。
"http:"や"https:"で始まるWeb上のURLのみが有効で、"C:¥"などで始まるドライブ名(LANサーバー名)+フォルダー名+ファイル名を指定するとエラーとなります。
なおURLの後ろにクエリとしてクライアント側のデータを添付する場合は、「クエリ付のURL」を指定します。
第3引数(varAsync)は、操作が非同期的に行われるかどうかを指定します。
下で説明するsendメソッドを実行することで「リクエストを送信し、レスポンスを受け取る」事ができるのですが、
同期(False)を指定した場合は、レスポンスの受け取りが完了するまでは制御はsendメソッドに留まり、次のコードに移ることができません。
この同期状態はVBAでは普通のことなのですが、今回はインターネット上のやり取りなので、通信状態が悪かったり呼び出すファイルのサイズが大きかったりすると、画面がフリーズしたりユーザー操作が反応しない状態になったりする場合があります。
一方非同期(True)を指定した場合は、sendメソッドでリクエストを送信したらすぐに次のコードに移ります。しかし次行ではレスポンスがまだ戻ってきていない可能性が高いので、進み状況をreadyStateプロパティ値で監視する等の必要が出てきます。
この同期/非同期の既定値は、下記の様に生成するオブジェクトで異なるようです。なので必ず指定した方が良さそうです。
オブジェクト | 既定値 | |||
---|---|---|---|---|
同期(False) | 非同期(True) | |||
事 前 | MSXML2 | ServerXMLHTTP | 〇 | |
XMLHTTP | 〇 | |||
WinHttp | WinHttpRequest | 〇 | ||
実 行 時 | MSXML2 | ServerXMLHTTP | 〇 | |
XMLHTTP | 〇 | |||
Microsoft | XMLHTTP | 〇 | ||
WinHttp | WinHttpRequest5.1 | 〇 |
第4引数(bstrUser)・第5引数(bstrPassword)は、認証のためのユーザー名およびパスワードのようです。
3-2.send
リクエストをサーバーに送信するのがsendメソッドです。構文は以下です。XMLHTTP.send([varBody])
引数 | 型 | 内容 | ||
---|---|---|---|---|
1 | varBody | 省略可 | String | リクエストとともに送信されるメッセージ本文 |
引数(varBody)は、固定したテキストファイルを取得するだけなら省略(または Null を指定)でOKです。
一方、クライアント側からサーバー側にデータを送付する場合の内、POST法(メッセージボディにデータを載せる)を使用する時は引数(varBody)に文字列として渡す「データ」を指定します。詳細は「クライアント側からデータをサーバーに送付」で説明します。
なおSendでリクエストを送信した後、レスポンスのデータを待ちreadyStateプロパティ値が4の状態になってから次の行に制御が移るのが「同期」、レスポンスを待つこと無くすぐに次の行に制御が移るのが「非同期」です。
この同期・非同期を指定しているのが、Openメソッドの第3引数(同期=False、非同期=True)です。
上記のOpenメソッドとSendメソッドを使った、「Web上からテキストファイルを取得」する基本的なコードを示します。
- '========== ⇩(13) OpenとSendを使った基本的なコード ============
- Sub test008()
- Dim XHR As Object
- Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF8B.txt"
- Set XHR = CreateObject("Microsoft.XMLHTTP")
- With XHR
- .Open "GET", FN, False
- .send Null
- MsgBox .ResponseText
- End With
- Set XHR = Nothing
- End Sub
328行目「.Open "GET", FN, False」では、通信方法をGET法とし、323行目で設定したURLのテキストファイルに対してのリクエスト発信を準備しています。また第3引数はFalseと同期モードとしているため、Send以降のコードは「既にレスポンスは戻ってきている」ことになります。
329行目「.send Null」では、Nullを指定しているためメッセージボディにはデータを書き込まずに、リクエストを発信しています。引数のNullを省略して単に「.send」としても、もちろんOKです。
331行目「MsgBox .ResponseText」では、レスポンスのテキストデータを取得し、表示させています。
3-3.abort
abortメソッドを実行すると、Openメソッドによる送信準備のキャンセル、および既に送信されているリクエストを中止します。構文は以下で、引数はありません。XMLHTTP.abort
Openメソッドの直後にabortを実行すれば、(Openをしていない事になるので)Sendメソッド実行時にエラーが発生します。
Sendメソッドの直後にabortを実行すれば、Openを実行する前に戻ってしまいreadyStateもゼロとなります。またStatusプロパティも、responseText等の値もエラーとなります。
なおSetOption等で設定したプロパティ値は、abortを実行しても保持されるようです。
3-4.setRequestHeader
setRequestHeaderメソッドでは、HTTPリクエストのヘッダーの値を設定します。図05で言うと、クライアントからサーバーに送るHTTPリクエストの真ん中の部分に書かれる内容の設定です。構文は以下です。XMLHTTP.setRequestHeader(bstrHeader, bstrValue)
2つの引数には以下の内容を指定します。
引数 | 型 | 内容 | ||
---|---|---|---|---|
1 | bstrHeader | 必須 | String | ヘッダー名 |
2 | bstrValue | 必須 | String | 設定する値 |
setRequestHeaderメソッドを実行できる位置は、Openの後で且つSendの前のみです。
なお複数のヘッダー項目を設定する場合は、1つ1つのsetRequestHeaderメソッドでのヘッダ設定を複数回実行させます。
ヘッダー項目は大きく4つに分類されます。
一般(ジェネラル) | 要求と応答の両方で使われるヘッダ |
要求(リクエスト) | HTTPリクエストに使われるヘッダ |
応答(レスポンス) | HTTPレスポンスに使われるヘッダ |
ボディ情報(エンティティ) | ボディ部分の情報 |
実際のヘッダー項目の一部を、上記の分類ごとに以下に示します。setRequestHeaderですので応答(レスポンス)は必要ないのですが、下の方で説明する「getAllResponseHeadersメソッド」、「getResponseHeaderメソッド」と重複する部分が多いので一緒の表にしています。
ヘッダ項目 | 内容 | 値の例 | 設定可 | |
---|---|---|---|---|
一 般 | ||||
Connection | 現在の接続を維持するか否か | Keep-Alive または none | ||
Keep-Alive | 持続を維持する期間 | timeout=5, max=100 | ||
Date | 送付した日時 | Mon, 18 Jul 2016 16:06:00 GMT | ||
要 求 | ||||
Accept | クライアントが受け入れ可能な種類 | */* | 〇 | |
Accept-Language | クライアントが受け入れ可能な言語コード | ja-JP | 〇 | |
User-Agent | ブラウザのソフト名 | Mozilla/4.0 | ||
Host | リクエスト先サーバーのドメイン名 | atsumitm.iobb.net | ||
If-Modified-Since | 指定日時より最新のリソースの場合のみデータ取得 | Mon, 11 Jul 2016 12:00:00 GMT | 〇 | |
Cache-Control | キャッシュ機能設定 | no-cache | 〇 | |
応 答 | ||||
Accept-Ranges | サーバーが範囲付きリクエストに対応する場合、その範囲の単位 | bytes | ||
Etag | リソースの識別バージョン | "3f-61c68d0ba92bb" | ||
Server | サーバーのソフトウェア名 | Apache | ||
ボ デ ィ 情 報 | ||||
Content-Type | ボディのメディアタイプ | text/plain | 〇 | |
Content-Length | リソースの大きさ(バイト単位) | 63 | ||
Last-Modified | リソースが最後に変更された日時 | Mon, 18 Jul 2016 02:36:04 GMT |
なおsetRequestHeaderメソッドでクライアント側から設定可能なのは、上表の右端列の〇印の項目だけのようです(表に載せた以外の項目の中には、設定可能な項目も存在するようです)。
サーバー上の固定ファイル(テキストファイルやHTMLファイル)を扱うのであれば、setRequestHeaderメソッドによるヘッダの設定は不要で、通信上必要となる項目は自動的にヘッダ設定されます。
しかし「クライアント側からデータをサーバーに送付」の中で説明するPOST法で「メッセージボディにパラメータ(=データ)を添付」する場合には、その添付データの種類をContent-Typeに指定します。このデータの種類は「MIMEのメディアタイプ」と呼ばれているようです。
Content-Type | 内容 |
---|---|
text/plain | テキストファイル |
text/html | HTMLファイル |
text/xml | XMLファイル |
text/csv | CSVファイル |
text/css | CSSファイル |
text/javascript | JavaScriptファイル |
text/vbscript | VBScriptファイル |
application/json | JSONファイル (例: {“email”:"xxxx",”id”:"YYYY"}) |
application/x-www-form-urlencoded | キーと値が "="で結ばれた形でエンコード キーと値は "&"で区切られる (例:email=xxxx&id=YYYY) |
application/x-httpd-cgi | CGIスクリプト |
application/msword | Word文書 |
application/pdf | PDFファイル |
application/zip | Zipファイル |
image/jpeg | JPEGファイル(.jpg, .jpeg) |
image/png | PNGファイル |
image/gif | GIFファイル |
image/svg+xml | SVGファイル |
video/mpeg | MPEGファイル(動画) |
setRequestHeaderメソッドを指定しない状態(=既定)では Content-Typeは「text/html」となっているようです。「POST法でクライアントデータを送信」で説明するPOST法では、データを「キー = 値」という形で送るのですが、既定状態(=無指定)ではPOST法によるデータとは認識してくれないようです。
ですのでPOST法でデータを渡す場合は、Content-typeに「application/x-www-form-urlencoded」の指定が必要となります
また応答速度の高速化やサーバーへの負担軽減という目的から、Web上のファイルを色々な場所で「キャッシュ」という形で一時保管している場合があります。ですので、サーバー上でファイルを書き換えた直後は、クライアント側には「書き換える前の古いファイル(=キャッシュ値)」が戻る場合があります。(時間が経てば、キャッシュも最新状態に更新されます)
この対策として、SetRequestHeadeメソッドを使う事で「キャッシュを無効にし、最新の実ファイルの内容を取得」することが出来ます。以下がそのコード例です。
- '========== ⇩(14) SetRequestHeaderメソッドで最新内容を取得 ============
- Sub test009()
- Dim XHR As Object
- Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF8B.txt"
- Set XHR = CreateObject("Microsoft.XMLHTTP")
- With XHR
- .Open "GET", FN, False
- .SetRequestHeader "Pragma", "no-cache" '←HTTP/1.0用
- .SetRequestHeader "Cache-Control", "no-cache" '←HTTP/1.1用
- .SetRequestHeader "If-Modified-Since", "Thu,01 Jun 1970 00:00:00 GMT" '←IE用?
- .send
- MsgBox .ResponseText
- End With
- Set XHR = Nothing
- End Sub
実ファイルを参照する方法には以下の3種類があるようです。
①XMLHTTP.SetRequestHeader "Pragma", "no-cache"
②XMLHTTP.SetRequestHeader "Cache-Control", "no-cache"
③XMLHTTP.SetRequestHeader "If-Modified-Since", "極端に古い日時"
①の"Pragma"はHTTP/1.0の古い通信プロトコル用、②の"Cache-Control"はHTTP/1.1の新しい通信プロトコル用です。
また③の"If-Modified-Since"は、指定した日時以降にファイルが更新されている場合はレスポンスを返し、更新されていなければ304ステータス(更新されていない:図19)を返すというものです。なので極端に古い日時を指定しておけば、サーバー上にある最新ファイルを取得できるという理屈です。
問題は①~③の内で「確実に最新ファイルを戻すのはどれか」という事ですが、色々試してみたのですが良く分かりませんでした。ですので360~362行目のように、全てを列記しておくのも1つの手かと思います。
3-5.waitForResponse
非同期(Openメソッドの第3引数=True)でリクエストを送信する時には、Sendメソッド実行後「readyState=4(レスポンスの受け取りが完了)になるまで待つ」必要があります。そのため図18の51~53行目ではDo~Loopを使っています。このレスポンスを「一定時間だけは待つ」のがwaitForResponseメソッドです。構文は以下です。
XMLHTTP.waitForResponse([timeoutInSeconds]) As Boolean
引数には、以下の様にレスポンスを待つ「秒数」を指定します。
引数 | 型 | 内容 | ||
---|---|---|---|---|
1 | timeoutInSeconds | 省略可 | 数値 | レスポンスを待つ時間(秒単位) |
引数の既定値は「-1(INFINITE:無限大)」なので、引数を指定しない場合はずっと待ち続けるようです。ですので既定のままだと、ちょっと危険かもしれません。
設定値のデータ型は明記されていませんが、LongLong型を超える値を指定してもエラーとはなりません。また、小数点のある値を指定してもエラーとはなりませんが、例えば 0.5を設定するとゼロと見なされるようで、Round関数のような偶数側に丸める方式になっているようです。
戻り値はBoolean型で、True・Falseの内容は以下の内容になります。
・True=指定時間内にレスポンスを受信した(ReadyStateが4になった)
・False=指定時間内にレスポンスが返らず、タイムアウトが発生した
Trueになると、指定した時間に達していなくても、waitForResponseメソッドの次の行に制御が移ります。
この様子を図にしたのが以下です。waitForResponseの次にResponseTextでデータを取得しています。

図51
上図で青い太矢印が「waitForResponseメソッドで指定した秒数」としています。
Sendメソッドでリクエストがサーバーに向かって発信され、サーバーからはレスポンスが返ってきますが、waitForResponseメソッドで指定した秒数内でレスポンスが返ってくれば「次の行に制御が移行」し、左図のようにResponseText等でデータが取得できることになります。
しかし、通信環境やデータのサイズなどが原因でレスポンスが遅くなり、waitForResponseメソッドで指定した秒数内にレスポンスが返ってこなかった時には、右図のように制御が移った先のResponseTextを実行する段階で、ReadyStateが4になっていないためにエラーとなります。
なお、図51の左はwaitForResponseメソッドの戻り値はTrue、右はFalseとなるのですが、例えばURLが間違っていた等により正常にリクエストできなかった時にも「waitForResponseメソッドはTrueを戻し、次の行に制御が移る」事になります。その意味では戻り値のみで正常・異常を判断するのは危険であり、Stateプロパティ値を調べ正常か否かを調べる必要が出てきます。
またFalseになると、図51の右側のようにwaitForResponseメソッドの次の行に制御が移りますが、リクエストが中断する訳ではないので、Do~Loopなどで待機していればレスポンスを受け取る事が可能です。
waitForResponseメソッドを使ってレスポンスを待つコード例を以下に示します。
- '========== ⇩(15) waitForResponseメソッドでレスポンスを待つ ============
- Sub test010()
- Dim XHR As Object
- Const FN = "http://atsumitm.iobb.net/its/excel/" & "Test_UTF8N.txt"
- Dim Res As Boolean
- Set XHR = CreateObject("MSXML2.serverXMLHTTP.6.0") '←server系またはWinHttp系が必要
- With XHR
- .Open "GET", FN, True '←非同期
- .send
- Res = .WaitForResponse(10) '←最大10秒間レスポンスを待つ
- If Res = False Then
- MsgBox "時間内にレスポンスを取得できませんでした。"
- Exit Sub
- End If
- If Not .Status = 200 Then Exit Sub
- MsgBox .responseText
- End With
- Set XHR = Nothing
- End Sub
399行目「.Open "GET", FN, True」では、非同期(Openメソッドの第3引数がTrue)の設定にしていますので、400行目「.send」でリクエストを送信した直後に、制御は402行目「Res = .WaitForResponse(10)」に移動しています。このWaitForResponse(10)では10秒の待機時間としましたので「10秒間まではレスポンスを待つ」事になります。
指定秒数内にレスポンスが返ってきた場合は、WaitForResponseメソッドはTrueを戻します。一方指定秒数内にレスポンスが来なかった場合はFalseが戻りますので、404行目「If Res = False Then」で仕訳をして、405行目「MsgBox "時間内にレスポンスを取得できませんでした。"」でメッセージを出し、406行目「Exit Sub」でプロシージャを終了しています。
しかしTrueが戻ったからと言ってもURLミス等の場合もあるので、409行目「If Not .Status = 200 Then Exit Sub」で、Statusプロパティが正常か否かを調べています。
なお、10秒より長い時間を設定してもOKです。しかし既定値(-1:無制限に待つ)はもちろん、あまりにも長い時間待ち続けるとプログラムが止まったままになってしまうため、実績から見て常識的な待ち時間にするのが良いと思われます。
なお同期でリクエスト(Openメソッドの第3引数=False)した時でもwaitForResponseメソッドを実行することは可能ですが、Sendメソッドの次の行に制御が移動した時には既に「readyState=4」となっているため、waitForResponseの戻り値は常にTrueとなり、待ち時間はゼロ(waitForResponseメソッドを実行した意味が無い)となります。
3-6.setTimeouts
setTimeoutsメソッドは、タイムアウトの設定を「ミリ秒単位」で指定します。ゼロを指定した場合は「タイムアウトが無い(=無限に待つ)」設定となります。構文は以下です。XMLHTTP.setTimeouts(resolveTimeout, connectTimeout, sendTimeout, receiveTimeout)
4つの引数の内容は以下です。
引数 | 型 | 内容 | 既定TimeOut時間 | ||
---|---|---|---|---|---|
1 | resolveTimeout | 必須 | Long | ドメイン名の解決のTimeOut時間 (ホスト名をIPアドレスにマッピングする時間) | 無し |
2 | connectTimeout | 必須 | Long | サーバーへの接続の確立のTimeOut時間 (ターゲットサーバとの通信ソケットを確立する時間) | 60秒 |
3 | sendTimeout | 必須 | Long | データの送信のTimeOut時間 (リクエストデータ(もしあれば)の個々のパケットを通信ソケット上で ターゲットサーバーに送信する時間) | 30秒 |
4 | receiveTimeout | 必須 | Long | 応答の受信のTimeOut時間 (ターゲットサーバーから応答データのパケットを受信する時間) | 30秒 |
ヘッダ項目Keep-Aliveの中に現れる「timeout」は「待機状態の接続を開いたままにしておく必要のある最小時間 (秒単位) 」なので、上表のどれにも該当しないようです。またKeep-Aliveの中の「Max」は「接続を閉じる前にこの接続で送信できるリクエストの最大数」なので時間では無く、単位は回数です。
既定のTimeOut時間は、どれも「こんなに長時間で良いの?」と思ってしまうような時間ですが、特に必要が無い限りは既定のまま(=設定しない)で良いと思われます。
なお、setTimeoutsメソッドを実行する場合は、openメソッドの前に実行する必要があります。
3-7.setProxy
setProxyメソッドは、プロキシの設定をします。構文は以下です。XMLHTTP.setProxy(proxySetting, [varProxyServer], [varBypassList])
3つの引数の内容は以下になります。
引数 | 型 | 内容 | |||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | proxy | 必須 | HTTPREQUEST SXH |
| |||||||||||||||
2 | varProxy | 省略可 | String | プロキシサーバー名のリスト | |||||||||||||||
3 | varBypass | 省略可 | String | ホスト名やIPアドレスのリスト |
図54
プロキシ(サーバー)とは、クライアントPCと同一LAN上に設置され、クライアントとインターネットの中継をするものです。目的はLAN上のセキュリティ向上で、URLフィルタリング(危ないURLに接続しない)、ログ取得(異常時の調査容易化)、マルウェアのスキャン(危険を持ち込まない)などが集中的に行えます。

図55
第1引数(proxySetting)には「プロキシをどうするか」を指定します。
値=0を指定すると、PCに設定されているプロキシ設定を使用します。それはWindowsのレジストリから設定値が取得される事になります。
値=1を指定すると、プロキシサーバーのデータを使用せず、直接Webサーバーにアクセスします。プロキシサーバーが存在しない場合は、この値を設定します。
第1引数に値=2を指定すると、第2・第3引数の値を適用します。
第2引数(varProxyServer)にはプロキシサーバーの名前、またはプロキシサーバーのリストを指定します。
第3引数(varBypassList)には、プロキシサーバーとの通信を許可したいホスト名、またはIPアドレスのリストを指定します。
3-8.setOption
setOptionメソッドは、URLの処理方法とSSL証明書関連の設定です。構文は以下です。XMLHTTP.setOption(option, value)
2つの引数の内容は以下になります。
引数 | 型 | 内容 | ||
---|---|---|---|---|
1 | option | 必須 | SERVERXMLHTTP_OPTION(図57) | 設定する種類 |
2 | value | 必須 | Variant | 設定値 |
このsetOptionメソッドの実行位置ですが、URL関係(第1引数が0または1)の場合は「Openより前に実行」することで有効となる事が確認できました。しかし、SSL関係(第1引数が値=2または3)の時は確認できていません。しかし同じメソッドですので、(たぶん)Openより前に実行することで有効になると思われます。
第1引数(option)の値は、以下(SERVERXMLHTTP_OPTION列挙型)の4つの中から選択します。
定数 | 値 | 内容 |
---|---|---|
SXH_OPTION_ | 0 | URLの文字列をシングルバイト変換する時の文字コード |
SXH_OPTION_ | 1 | True=URL内の%文字をエスケープする False=%文字はそのまま |
SXH_OPTION_ | 2 | SSL証明書エラーのマスク設定 |
SXH_OPTION_ | 3 | 送信するクライアント証明書を設定 |
第2引数(value)は、当然ながら第1引数にどれを指定するかで変わってきます。
まず第1引数に「SXH_OPTION_URL_CODEPAGE(値=0)」を指定した場合は、URLの文字コードとして以下の値を第2引数に指定します。
定数 | 値 | 説明 |
---|---|---|
CP_ACP | 0 | ANSI コードページ |
CP_OEMCP | 1 | OEM コードページ |
CP_MACCP | 2 | Macintosh コードページ |
CP_THREAD_ACP | 3 | 現在のスレッドの ANSI コードページ |
CP_SYMBOL | 42 | シンボルコードページ |
CP_UTF7 | 65000 | UTF-7 を使った変換 |
CP_UTF8 | 65001 | UTF-8 を使った変換(既定 ?) |
- | 932 | SHIFT-JIS |
- | 51932 | EUC-JP |
- | 50220 | JIS.ISO-2022-JP |
- | 50932 | 自動選択 |
URL内や、URLの後ろにパラメータとして付加した文字に「アルファベットや数字以外の文字」が入る場合には、この設定値が影響してきます。実際に全角文字が入ったもので試してみるとUTF-8(既定 ?)以外の設定では、ファイルまで辿り着かなかった(404エラー)り、パラメータが正しく渡らなかったりします。
なおこれは、WinHttp系のOptionプロパティに引数=2を指定したものと同機能のようです。
![]() 上記で、影響を受ける文字を「アルファベットや数字以外の文字」と説明しましたが、リクエストデータを見てみると全角文字だけでは無く "=" のような記号も影響を受けるようです。なので「ASCII以外」では無いというのは少し意外です。 また「なぜUTF-8でないとダメなのか」についてですが、WindowsやExcelの文字コードはUTF-8では無いので対象外となりそうです。では図15のファイルを置いてあるサーバー(atsumitm.iobb.net)のO/Sの文字コードがUTF-8(確認済み)だからなのか、または他の理由によるものなのかが良く分かりません。 しかし、もしサーバーの設定文字コードで決まるとすれば、日本語を含んだファイル名をリクエストする場合は「そのサーバーに対応した文字コード設定」をする必要が出てくる事になり、相当やっかいな問題です。 |
「SXH_OPTION_ESCAPE_PERCENT_IN_URL(値=1)」は、Openの第2引数にしているURLに含まれている「%文字」をエスケープするか否かを設定するものです。
setOption(1, True) のように指定してエスケープすると、%文字は「%25」となります。既定はFalse(%文字はそのまま)です。なお「半角スペース」は、True・Falseに関わらず「%20」となります。
これは、WinHttp系のOptionプロパティに引数=3を指定したものと同機能のようです。
「SXH_OPTION_IGNORE_SERVER_SSL_CERT_ERROR_FLAGS(値=2)」は、SSL証明書関連でエラーが発生する場合、どのエラーを無視するかの設定です。無視するエラー内容は以下になります。
定数 | 値 | 説明 |
---|---|---|
SXH_SERVER_ | 256 | 不明な認証局 |
SXH_SERVER_ | 512 | サブジェクト名のない証明書など、不正な形式の証明書。 |
SXH_SERVER_ | 4096 | 訪問したホスト名とサーバーで使用されている証明書名が不一致。 |
SXH_SERVER_ | 8192 | 証明書の日付が無効、または有効期限切れ。 |
SXH_SERVER_ | 13056 | すべての証明書のエラー(既定) |
既定はSXH_SERVER_CERT_IGNORE_ALL_SERVER_ERRORS(値=13056)なので、SSL証明書関連のエラーは「全て無視」する設定になっています。例えば 証明書の日付エラーだけを検出するのであれば「XMLHTTP.setOption(2, 13056 - 8192)」のようにします。
これは、WinHttp系のOptionプロパティに引数=4を指定したものと同機能のようです。但し既定値は異なるようです。
「SXH_OPTION_SELECT_CLIENT_SSL_CERT(値=3)」は、サーバーがクライアント証明書(クライアントの身元を証明するための電子証明書)を要求する場合、どの証明書をクライアント側から送付するかを設定するものです。
第2引数にはクライアント証明書の名前(String型)を指定するとありますが、レジストリ位置を指定すると説明しているサイトもあります。どれが正しいのか、どれも正しいのか良く分かりません。なお既定(=空文字列)の場合、リストの一番上の証明書が選択されるみたいですが、リストがどれなのかも分かりません。
なおこれは、WinHttp系のOptionプロパティに引数=5を指定したものと同機能のようです。
3-9.setProxyCredentials
setProxyCredentialsメソッドは、プロキシ認証情報であるユーザー名とパスワードを指定します。構文は以下です。XMLHTTP.setProxyCredentials(bstrUserName, bstrPassword)
2つの引数の内容は以下です。
引数 | 型 | 内容 | ||
---|---|---|---|---|
1 | bstrUserName | 必須 | String | 認証されるユーザー名 |
2 | bstrPassword | 必須 | String | 認証されるユーザーのパスワード |
第1引数(bstrUserName)にはプロキシサーバーに入るためのユーザー名を、第二引数(bstrPassword)にはそのパスワードを指定します。
なおこれは、WinHttp系のsetCredentialsメソッドに第3引数=1を指定したものと同機能のようです。
3-10.setClientCertificate
setClientCertificateメソッドは、HTTPSサーバーに送信するクライアント証明書を設定します。構文は以下です。XMLHTTP.SetClientCertificate(ClientCertificate As String)
引数には「クライアント証明書」を指定します。
引数 | 型 | 内容 | ||
---|---|---|---|---|
1 | ClientCertificate | 必須 | String | クライアント証明書 |
Microsoftサイトによると、引数(ClientCertificate)には、クライアント証明書の場所(レジストリ位置?)、 証明書ストア(証明書が格納されるストレージ)、サブジェクト(証明書を発行するエンティティーのID情報が含まれる識別名)を指定するとの事です。
内容的にはsetOptionメソッドで、第1引数にSXH_OPTION_SELECT_CLIENT_SSL_CERT(値=3)を指定するのと同機能のようです。但しsetOptionはMSXML2系のみで使えるメソッドであるのに対し、setClientCertificateはWinHttp系のみで使えるメソッドです。
3-11.setCredentials
setCredentialsメソッドは、HTTPサーバーに使用する資格情報を指定します。情報の設定先はプロキシサーバーまたはWebサーバーのどちらかを指定します。構文は以下です。XMLHTTP.SetCredentials(UserName, Password, Flags)
3つの引数の内容は以下になります。
引数 | 型 | 内容 | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | UserName | 必須 | String | 認証のユーザー名 | |||||||||
2 | Password | 必須 | String | 認証のパスワード | |||||||||
3 | Flags | 必須 | HTTPREQUEST |
|
Webサーバー側とプロキシサーバー側の両方について認証をしなければならない場合は、Webサーバー側・プロキシサーバー側と2回に分けてsetCredentialsメソッドを実行する必要があるようです。
なおこのメソッドの第3引数に値=1を指定したものは、ServerXMLHTTP系のsetProxyCredentialsメソッドと同機能のようです。
3-12.setAutoLogonPolicy
setAutoLogonPolicyメソッドは、自動ログオンポリシーを指定します。構文は以下です。XMLHTTP.SetAutoLogonPolicy(AutoLogonPolicy)
引数(AutoLogonPolicy)は WinHttpRequestAutoLogonPolicy列挙型で、以下の3種から選択します。
定数 | 値 | 内容 |
---|---|---|
AutoLogonPolicy_Always | 0 | すべての要求に対し、既定の資格情報を使用して認証されたログオンが実行される |
AutoLogonPolicy_OnlyIfBypassProxy | 1 | 既定の資格情報を使用して認証されたログオンは、LAN上の要求に対してのみ実行される(既定) |
AutoLogonPolicy_Never | 2 | 認証は自動的には使用されない |
何度読み返しても、どのサーバーに対しての設定なのかも含めて、内容は良く分かりません。
3-13.getAllResponseHeaders
getAllResponseHeadersメソッドは、HTTPレスポンスに添付された全レスポンスヘッダーを文字列で返します。レスポンスヘッダ同士はvbCrLf(0x0D0A)で区切られます。構文は以下で、引数はありません。XMLHTTP.getAllResponseHeaders() As String
レスポンスヘッダーには多くの種類がありますが、その一例が図47(「要求(リクエスト)」専用のヘッダ項目を除く)です。しかし全種類が戻る訳では無く、そのレスポンスヘッダの内「HTTPレスポンスに添付された項目のみ」が戻されます。
コード例が下記です。
- '========== ⇩(16) GetAllResponseHeadersでレスポンスヘッダ情報を取得 ============
- Sub test011()
- Dim XHR As Object
- Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF8B.txt"
- Set XHR = CreateObject("MSXML2.XMLHTTP.6.0")
- With XHR
- .Open "GET", FN, True
- .send
- Do Until .readyState = 4
- DoEvents: DoEvents
- Loop
- If Not .Status = 200 Then Exit Sub
- MsgBox .GetAllResponseHeaders
- End With
- Set XHR = Nothing
- End Sub
466行目「MsgBox .GetAllResponseHeaders」では、GetAllResponseHeadersメソッドを使ってHTTPレスポンスの全レスポンスヘッダ情報を表示させています。各ヘッダ情報は CrLf で区切られている為、ヘッダが羅列されて出力される事になります。
このGetAllResponseHeadersメソッドは、どの生成オブジェクトでも使用できます。上のコードでは455行目「Set XHR = CreateObject("MSXML2.XMLHTTP.6.0")」としていますが、下記の様に使用するオブジェクトで「HTTPレスポンスヘッダの内容は異なる」ようなので、もしより詳しい情報が必要な場合は、serverXMLHTTPなどのオブジェクトを使用します。

図65
3-14.getResponseHeader
getResponseHeaderメソッドは、引数に「取り出したいヘッダー項目(図47参照)」を指定することで、そのレスポンスヘッダーの値が返ります。構文は以下です。XMLHTTP.getResponseHeader(bstrHeader) As String
引数 | 型 | 内容 | ||
---|---|---|---|---|
1 | bstrHeader | 必須 | String | ヘッダー名 |
例えばレスポンスデータの長さ(ヘッダー「content-length」)を取得するのが、以下のコードです。
- '========== ⇩(17) getResponseHeaderメソッドでヘッダ情報を読み取る ============
- Sub test012()
- Dim XHR As Object
- Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16LEB.txt"
- Set XHR = CreateObject("MSXML2.XMLHTTP.6.0")
- With XHR
- .Open "GET", FN, True
- .send
- Do Until .readyState = 4
- DoEvents: DoEvents
- Loop
- If Not .Status = 200 Then Exit Sub
- MsgBox .GetResponseHeader("content-length")
- End With
- Set XHR = Nothing
- End Sub
496行目「MsgBox .GetResponseHeader("content-length")」では、GetResponseHeaderメソッドの引数に「"content-length"」を指定し、レスポンスデータの長さを取得し表示させています。
なお、レスポンスヘッダ内に「content-lengthヘッダ」が付いてこない場合もあるようで、その時は空文字列が表示されます。
注意点として、引数に""(長さゼロの文字列)を指定するとエラーとなります。また取得できるデータは「戻ってきたレスポンスヘッダ内の情報に限られる」ので、レスポンスヘッダ内には存在しないヘッダー名を指定したり、ヘッダー名のスペルが間違っていた場合は、値ゼロの文字列が返ります。なお、ヘッダー名の先頭や後端に半角スペースが入っていたり、大文字小文字の違いは大丈夫なようです。
また同名で複数のレスポンスヘッダーがあった場合は、値はカンマと空白で区切って接続した単一の文字列として返すそうです。
3-15.getOption
getOptionメソッドは、URL関係と証明書関係の設定値を取得します。構文は以下です。XMLHTTP.getOption(option) As Variant
引数(option)には下記のSERVERXMLHTTP_OPTION列挙型を指定します。
定数 | 値 | 内容 |
---|---|---|
SXH_OPTION_ | -1 | リソースのURL値 |
SXH_OPTION_ | 0 | URLの文字列をシングルバイト変換する時の文字コード |
SXH_OPTION_ | 1 | True=RL内の%文字をエスケープする False=%文字はそのまま |
SXH_OPTION_ | 2 | SSL証明書エラーのマスク種類 |
SXH_OPTION_ | 3 | 送信するクライアント証明書 |
上表はsetOptionメソッドの引数とほぼ同じです。異なる点は、SXH_OPTION_URL(値=-1)が追加されているのみで、これは「その時点でのURL」となります。つまり、
・「OpenとSendの間(図40の "b")」では、リクエストした時のURL
・「Sendの後(図40の "c")」では、レスポンス元のURL(リダイレクトされていた場合はリダイレクトURL)
が戻されます。ですので「Openの前(図40の "a")」でgetOption(-1)を実行すると、「リクエストするURLは、未指定」のためエラーとなります。
このことから図39では (a)bc と、"a"(Open前)をカッコ付きとしています。
値=0~3はsetOptionの内容と一緒です。
SXH_OPTION_URL_CODEPAGE(値=0)は、URL内の文字を変換する文字コードで、図58の内容となります。
SXH_OPTION_ESCAPE_PERCENT_IN_URL(値=1)は、URL内の%文字をエスケープするか否かです。
SXH_OPTION_IGNORE_SERVER_SSL_CERT_ERROR_FLAGS(値=2)は、SSL証明書関連のエラーのマスクで、内容は図59となります。
SXH_OPTION_SELECT_CLIENT_SSL_CERT(値=3)は、クライアント証明書です。
以下はgetOptionメソッドを使って、URL情報とSSL情報を取得しています。
- '========== ⇩(18) getOptionメソッドでURL設定やSSL設定の情報を取得 ============
- Sub test013()
- Dim XHR As Object
- Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16LEB.txt"
- Dim Str As String
- Dim i As Integer
- Set XHR = CreateObject("MSXML2.serverXMLHTTP.6.0")
- With XHR
- .Open "GET", FN, True
- .send
- Do Until .readyState = 4
- DoEvents: DoEvents
- Loop
- If Not .Status = 200 Then Exit Sub
- For i = -1 To 3
- Str = Str & i & vbTab & .getOption(i) & vbCrLf
- Next i
- MsgBox Str
- End With
- Set XHR = Nothing
- End Sub
529行目「Str = Str & i & vbTab & .getOption(i) & vbCrLf」では、getOptionメソッドを使って各情報を取得し、メッセージとして出力しています。その出力例が以下です。

図70
4.クライアント側からデータをサーバーに送付
以上は、サーバー上の「.htmlや.txt等の固定テキストファイル」の内容を取得する方法についての説明でした。一方サーバー上には、「クライアント側がデータを提供し、そのデータをサーバー側が処理をして組み立てたファイル」をクライアント側に戻すというシステムもあります。例えばYahooで検索項目を入力し検索ボタンをクリックすると、「入力した検索項目に合致したサイトを紹介」してくれるのも、クライアント側の入力したデータをYahooサーバーが処理をしているためです。
その場合には、クライアント側が入力したり準備したりしたデータを、パラメータとして「サーバー側に渡す」必要があります。その渡す手段には、下記のようにGET法とPOST法があります。

図71
GET法では、サーバーに渡すデータが「URLの後ろにパラメータとして付与」されます。この方法は、ブラウザのURLボックスの値をコピペさえすれば、クライアントの要求内容をサーバー側が処理した後のデータを「他の人にも配布可能」というメリットがあります。逆に、どんなデータを送ったのかがURL値で丸見えになる為、セキュリティ的には不利です。
一方POST法では、サーバーに渡すデータが「メッセージボディに書かれた状態」で送付されます。こちらはURLは不変のため「他の人には見られない状態でサーバーにデータを送付」することが出来、セキュリティ面で有利となります。
4-1.GET法でクライアントデータを送信
GET法でサーバーにデータを渡すには、以下のように「URLの後ろにパラメータとしてデータを添付」します。ここではGET法でのキーg1に「Aアあ」という値を、またキーg2には「Bイい」という値を渡しています。
- '========== ⇩(19) GET法でデータを送信 ============
- Sub test014()
- Dim XHR As Object
- Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_HTML.php" & "?g1=Aアあ&g2=Bイい"
- Set XHR = CreateObject("MSXML2.serverXMLHTTP.6.0")
- With XHR
- .Open "GET", FN, True
- .send
- Do Until .readyState = 4
- DoEvents: DoEvents
- Loop
- If Not .Status = 200 Then Exit Sub
- MsgBox .responseText
- End With
- Set XHR = Nothing
- End Sub
553行目「Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_HTML.php" & "?g1=Aアあ&g2=Bイい"」では、取得するファイル名「Test_HTML.php」の後ろに「?(クエスチョンマーク)」に続けて「キー = 値」という形でデータを渡します。複数渡す場合は「&」でつなぎます。
GET法を使用する場合は558行目「.Open "GET", FN, True」のように、Openメソッドの第1引数には「"GET"」を指定します。
559行目「.send」で、Sendメソッドを実行することでHTTPリクエストはサーバーに向けて送信される訳ですが、その時のHTTPリクエストの中身が以下になります。
- '========== ⇩(20) HTTPリクエストの内容(GET使用時) ============
- GET /its/excel/Test_HTML.php?g1=%Aアあ&g2=Bイい HTTP/1.1 '←リクエストライン
- Connection: Keep-Alive '←ここから4行はヘッダ
- Accept: */*
- User-Agent: Mozilla/4.0 (compatible; Win32; WinHttp.WinHttpRequest.5)
- Host: atsumitm.iobb.net
- (メッセージボディーは無し)
先頭行のURLに続けて、クライアント側からのデータが添付されていることが分かります。
![]() 図72等のコードを実行させた時のHTTPリクエストの内容は、Wireshark等のアプリで取得できます。しかし「https://」で始まるSSL/TLSで通信を行うサイトの場合は、リクエストの内容が「暗号化」されてしまい、送信した内容が確認できません。 図73では内容が視認できているように見えますが、これは送信先URLを「https:// → http://」にわざと変更させて通信した結果です。 |
なお「User-Agent」の項目のカッコ内の最後は「WinHttp.WinHttpRequest.5」となっていますが、オブジェクトとして「Winhttp.winhttprequest.5.1」を使用した時だけでは無く、どのオブジェクトを使用しても同じでした。という事は「通信の大元はWinhttp系のソフトが受け持っている」という事なのかもしれません。
4-2.POST法でクライアントデータを送信
POST法で「リクエストボディにデータを格納」してサーバーに渡す場合は、以下のようにSendメソッドの引数にクライアントのデータを指定します。ここではPOST法でのキーp1に「Cウう」という値を、キーp2に「Dエえ」という値を渡しています。
- '========== ⇩(21) POST法でデータを送信 ============
- Sub test015()
- Dim XHR As Object
- Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_HTML.php"
- Set XHR = CreateObject("MSXML2.serverXMLHTTP.6.0")
- With XHR
- .Open "POST", FN, True
- .setRequestHeader "Content-type", "application/x-www-form-urlencoded"
- .send "p1=Cウう&p2=Dエえ"
- Do Until .readyState = 4
- DoEvents: DoEvents
- Loop
- If Not .Status = 200 Then Exit Sub
- MsgBox .responseText
- End With
- Set XHR = Nothing
- End Sub
583行目「Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_HTML.php"」では、取得するファイル名「Test_HTML.php」の後ろには何もつけていません。
588行目「.Open "POST", FN, True」では、第1引数に "POST"を指定します。
590行目「.send "p1=Cウう&p2=Dエえ"」では、Sendメソッドの引数として「キー = 値」という形でデータを指定します。複数渡す場合は「&」でつなぎます。
589行目「.setRequestHeader "Content-type", "application/x-www-form-urlencoded"」では、リクエストボディに書き込むデータ(=Sendメソッドの引数)は「キー = 値」という形だ という指定をしています。
なおContent-type指定で、 "application/x-www-form-urlencoded" の後ろ側に文字コード指定として「;charset=UTF-8」を追加する例を良く見るのですが、VBAで試す限りはどの文字コードを指定しても結果は変わらないようです。
またJSONファイルの形式でPOSTデータを送付(もちろんContent-typeは "application/json" にして)した場合、今回のPHPファイルの設定($_POSTを使用)ではデータは受け取れません。ちょっと異なる処理が必要な様です(今回は省略します)。
送信されたHTTPリクエストの中身は以下の様になります。
- '========== ⇩(22) HTTPリクエストの内容(POST使用時) ============
- POST /its/excel/Test_HTML.php HTTP/1.1 '←リクエストライン
- Connection: Keep-Alive '←ここから5行はヘッダ
- Accept: */*
- User-Agent: Mozilla/4.0 (compatible; Win32; WinHttp.WinHttpRequest.5)
- Content-Length: 22
- Host: atsumitm.iobb.net
- p1=Cウう&p2=Dエえ '←メッセージボディー
メッセージボディにクライアントデータが書き込まれるのと同時に、ヘッダーに「Content-Length(ボディーのデータの長さ)」が自動的に追加されているのが分かります。
4-3.クライアントデータを受け取ったサーバー側での処理
データを受け取って処理をする「Test_HTML.php」の方は、以下のような内容になっています。- '========== ⇩(23) クライアントデータの処理例 ============
- GET1 :<?php
- print $_GET['g1'];
- ?>
- GET2 :<?php
- print $_GET['g2'];
- ?>
- POST1:<?php
- print $_POST['p1'];
- ?>
- POST2:<?php
- print $_POST['p2'];
- ?>
このPHPファイルに、GET及びPOSTでデータを送った場合(図72及び図74)には、以下のようなメッセージが返ります。

図77
なおPOSTでリクエストする際、Sendメソッドの引数にデータを指定し、且つ「URLの後ろ側にパラメータを追加」したのが以下のコードです。
- '========== ⇩(24) Readメソッドで指定文字数分を読み取る ============
- Sub test016()
- Dim XHR As Object
- Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_HTML.php" & "?g1=Aアあ&g2=Bイい"
- Set XHR = CreateObject("MSXML2.serverXMLHTTP.6.0")
- With XHR
- .Open "POST", FN, True
- .SetRequestHeader "Content-type", "application/x-www-form-urlencoded"
- .send "&p1=Cウう&p2=Dエえ"
- Do Until .readyState = 4
- DoEvents: DoEvents
- Loop
- If Not .Status = 200 Then Exit Sub
- MsgBox .ResponseText
- End With
- Set XHR = Nothing
- End Sub
この場合、下図右側のように「URLに追加したパラメータ」+「Sendの引数で指定したパラメータ」の両方ともが戻されます。
しかしOpenの第1パラメータに、POSTの代わりに「GETを指定」した場合は、下図左側のように「URLに追加したパラメータ」のみが戻ります。

図79
アプリ実例・関連する項目
「計算や検索を行うサイトからデータを取得する」「自分専用の関数を作る」
「祝日を自動反映するカレンダー」
サンプルファイル
今回、説明の中で紹介したコードは、以下のサンプルファイルの標準モジュール(Module1)に記載しています。実行するにはVBEから直接実行してください。
セキュリティ向上を目的として「インターネット経由でダウンロードしたOfficeファイル(Excel等)のマクロは、既定でブロック」されるようにOfficeアプリケーションの既定動作が変更になりました。(2022年4月より切替開始) 解除の方法については「ダウンロードファイルのブロック解除方法」を参照下さい。 |