2024/12/30

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




VBAを使い「テキストファイルを読み書き」する手法について、以下のようなシリーズで紹介しています。
 ①テキストの文字コードについて
 ②Openステートメント法による読み書き
 ③ADODB.Stream法による読み書き
 ④TextStream法による読み書き
 ⑤XMLHTTP法によるWebデータの読み取り   ←今回
 ⑥Web上からダウンロードしての読み取り
XMLHTTPオブジェクトは、HTTP通信を使ってWebサーバーに対してリクエスト(データの要求)を行い、レスポンス(応答)してきたデータを受け取る機能を持っています。この機能を使うことで、Webサーバー上にあるテキストファイルの内容を読み取ることができます。今回はこのXMLHTTP法を紹介します。
この「XMLHTTP法」は基本的には文字コードUTF-8のみの対応ですが、ADODB.Stream等と組み合わせる事で複数の文字コードに対応できます(下表)。なお操作可能なのは、Web上(http:// や https:// で始まる場所)のファイルのみです。
読み書き手法対応文字コードファイルの場所
Shift-JISUTF-8UTF-16LAN上Web上
Openステートメント
ADODB.Stream
TextStream(FileSystemObject)
XMLHTTP+ADODB.Stream(〇)(〇)
図01

上表のように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」で良いと思います)。
XMLHTTPの参照設定
図06

「ライブラリーを参照設定」した上で、プログラム的には図07のように「オブジェクト変数をXMLHTTPオブジェクトとして宣言」→「New句を使って生成」します。
  1. '========== ⇩(1) 事前バインディングでの宣言と生成 ============
  2.  Dim XHR As ServerXMLHTTP60      '←XMLHTTPオブジェクト型変数の宣言
  3.  
  4.  Set XHR = New ServerXMLHTTP60   '←XMLHTTPオブジェクトの生成
  5.  
  6.   (作成したXMLHTTPオブジェクト変数(XHR)を使い、テキスト処理)
図07

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
図08

寄り道(XMLHTTPとServerXMLHTTPの違い)
図07では、ServerXMLHTTP60をデータ型として指定しました。しかしMSXML2には「XMLHTTP60」のように"Server"というのが付いていないオブジェクト型があります。
このServerが付いたものと付かないものでは使えるメソッドの種類が異なり、またバージョンによっても異なるようなので下表にまとめました。同時にWinHttpRequestについても併記しています。
MSXML2WinHttp
ServerXMLHTTPXMLHTTPWinHttpRequest




readyState
(onreadystatechange)
status
statusText
responseBody
responseStream
responseText
responseXML
option



open
send
abort
setRequestHeader
waitForResponse
setTimeouts
setProxy*1
setOption
setProxyCredentials*1
setClientCertificate
setCredentials
setAutoLogonPolicy
getAllResponseHeaders
getResponseHeader
getOption
図09

*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オブジェクトの生成をします。
  1. '========== ⇩(2) 実行時バインディングでの宣言と生成 ============
  2.  Dim XHR As Object   '← 一般オブジェクト型変数の宣言
  3.  
  4.  Set XHR = CreateObject("MSXML2.ServerXMLHTTP.6.0")   '←XMLHTTPオブジェクトの生成
  5.  
  6.   (作成したXMLHTTPオブジェクト変数(XHR)を使い、テキスト処理)
図10

21行目「Dim XHR As Object」では、単なるObject型として変数宣言をします。
23行目「Set XHR = CreateObject("MSXML2.ServerXMLHTTP.6.0")」では、CreateObject関数を使ってXMLHTTPオブジェクトを生成します。
寄り道(CreateObjectに指定するクラス名)
23行目でCreateObject関数に渡している引数は「"MSXML2.ServerXMLHTTP.6.0"」としています。XMLHTTPオブジェクトを生成する場合、この引数(オブジェクトのアプリケーション名+クラス名)を様々な値に設定する事が可能です。
下記ではCreateObject関数に設定可能な値と、それに必要なライブラリファイル名を示します。見え消しで無いのが設定可能のものです(PCの環境により、異なる可能性がありますので御注意下さい)。
なお、対応するライブラリファイル名は私の推定です。
ライブラリファイル(推定)機能の
分類
msxml3.dllmsxml6.dll ? winhttpcom.dll
or winhttp.dll
1MSXML2.ServerXMLHTTP.6.0A
2MSXML2.ServerXMLHTTP.5.0
3MSXML2.ServerXMLHTTP.4.0
4MSXML2.ServerXMLHTTP.3.0A
5MSXML2.ServerXMLHTTPA
6Microsoft.ServerXMLHTTP
7MSXML2.XMLHTTP.6.0B
8MSXML2.XMLHTTP.5.0
9MSXML2.XMLHTTP.4.0
10MSXML2.XMLHTTP.3.0B
11MSXML2.XMLHTTPB
12Microsoft.XMLHTTPB
13Microsoft.XMLHTTP.1.0B
14WinHttp.WinHttpRequest.5.1C
図11

クラス名の後ろの数字はバージョンを表します。例えば「MSXML2.ServerXMLHTTP.6.0」は最新のバージョン6.0です。
バージョンの内「5.0」「4.0」は、現在ではMicrosoftの方でバグ修正が行われない状態となっており、最新のO/Sには対応するライブラリファイルもインストールされていない様です。
但しバージョン「3.0」については現役で、広範囲に利用されているようです。なおバージョンを省略(表の5番や11番)すると、バージョン3.0と判断されるようです。
またアプリ名を表す接頭辞には、「MSXML2」「Microsoft」「WinHttp」の3種類があります。
Microsoft接頭辞は古いため「使わない方が良い」と説明しているサイトも見かけますが、一応正しく動きます。

寄り道(クラスのServer版と一般版の違い)
よりみち」で説明したように、事前バインディングの時にも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」とその分類記号を記しました。
図11の右端列 A  B  C 
MSXML2
ServerXMLHTTP
MSXML2
XMLHTTP
Microsoft
XMLHTTP
WinHttp
WinHttpRequest




readyState
onreadystatechange
status
statusText
responseBody
responseStream
responseText
responseXML
option



open
send
abort
setRequestHeader
waitForResponse
setTimeouts
setProxy
setOption
setProxyCredentials
setClientCertificate
setCredentials
setAutoLogonPolicy
getAllResponseHeaders
getResponseHeader
getOption
図12

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メソッドはイベントの機能なので、表からは除外しています。
まずは設定項目についてまとめたのが以下になります。
設定項目MSXML2MicrosoftWinHttp
ServerXMLHTTPXMLHTTPXMLHTTPWinHttpRequest
ヘッダ
リクエストヘッダsetRequestHeadersetRequestHeadersetRequestHeader
応答ヘッダのサイズOption
URL等
URLの文字コードsetOptionOption
URLの%文字のエスケープsetOptionOption
不安全文字のエスケープOption
時間
タイムアウトsetTimeoutssetTimeouts
レスポンス待ち時間waitForResponsewaitForResponse
リダイレクト
自動リダイレクトOption
HTTPへのリダイレクトOption
リダイレクト最大数Option
証明書
クライアント証明書setOptionsetClientCertificate
Option
サーバー証明書エラーのマスクsetOptionOption
証明書失効チェックOption
Passport認証Option
HTTP/1.1の使用Option
承認状態を戻すOption
サーバー
プロキシ設定setProxysetProxy
プロキシのID・PWsetProxyCredentialssetCredentials
WebサーバーのID・PWsetCredentials
自動ログオンポリシーsetAutoLogonPolicy
パスワード拒否Option
ユーザーエージェントOption
トラフィック監視Option
再接続のサイズOption
図13

次に取得情報が以下です。
取得情報MSXML2MicrosoftWinHttp
ServerXMLHTTPXMLHTTPXMLHTTPWinHttpRequest
状態
オブジェクトの進行状態readyStatereadyState
やり取りの状態status
statusText
status
statusText
status
statusText
取得データ
テキストデータresponseTextresponseTextresponseText
バイナリデータresponseBodyresponseBodyresponseBody
Stream(responseStream)(responseStream)(responseStream)
XMLデータresponseXMLresponseXML
ヘッダ
ヘッダ情報getAllResponseHeaders
getResponseHeader
getAllResponseHeaders
getResponseHeader
getAllResponseHeaders
getResponseHeader
応答ヘッダのサイズOption
URL等
URLgetOptionOption
URLの文字コードgetOptionOption
URLの%文字のエスケープgetOptionOption
不安全文字のエスケープOption
リダイレクト
自動リダイレクトOption
HTTPへのリダイレクトOption
リダイレクト最大数Option
証明書
クライアント証明書getOption
サーバ証明書エラーのマスクgetOptionOption
証明書失効チェックOption
Passport認証Option
HTTP/1.1の使用Option
承認状態を戻すOption
サーバー
パスワード拒否Option
ユーザーエージェントOption
トラフィック監視Option
再接続のサイズOption
図14

表の各列を見比べると、最も充実しているように見えるのは「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.txtShift-JIS-"Aアあ123"
"Web上のファイル"
"文字コード〇〇(BOM有無)"
Test_UTF8N.txtUTF-8無し
Test_UTF8B.txtUTF-8付き
Test_UTF16LEN.txtUTF-16LE無し
Test_UTF16LEB.txtUTF-16LE付き
Test_UTF16BEN.txtUTF-16BE無し
Test_UTF16BEB.txtUTF-16BE付き
Test_XML.xmlUTF-8無し 下記内容のXMLファイル。コードは図29
種類価格
みかん130
りんご250
Test_HTML.phpUTF-8無し1~2行目:GET(g1=, g2=)で送った文字列
3~4行目:POST(p1=, p2=)で送った文字列
図15

2.XMLHTTPのプロパティ

プロパティは9種ありますが、以下の様に生成するオブジェクトの種類により使えるものが制限されます。
表の内容としては図09図12と同じですが、再掲します。
プロパティ事前バインディング実行時バインディング
MSXML2WinHttpMSXML2MicrosoftWinHttp
ServerXMLHTTPXMLHTTPWinHttpRequestServerXMLHTTPXMLHTTPXMLHTTPWinHttpRequest.5.1
readyState
onReadyStateChange
status
statusText
responseBody
responseStream
responseText
responseXML
option
図16

上記プロパティの内、一番下の「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が現れる」という現象になる可能性がありますので「不等号を使って状態を感知」するか、または「最終状態(=操作完了)か否かを感知」する方法が良さそうです。
定数状態
Unsent0XMLHTTPオブジェクトは作成済み
Opened1Openメソッドの呼び出し済み
Headers_Received2Sendメソッドが呼び出し済み+レスポンスヘッダを受信済み
Loading3レスポンスボディを受信中
Done4操作完了
図17

以下のサンプルコードではDo~Loopを使って状態4(操作完了)になるまで待ち、状態4になったら抜け出し次に移っています。
  1. '========== ⇩(3) readyStateでレスポンスが完了するまで待つ ============
  2. Sub test001()
  3.  Dim XHR As Object
  4.  Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF8N.txt"   '←UTF-8ファイル
  5.  Set XHR = CreateObject("MSXML2.XMLHTTP.6.0")
  6.  With XHR
  7.   .Open "GET", FN, True
  8.   .send
  9.   Do Until .readyState = 4   '←レスポンス完了まで待つ
  10.    DoEvents: DoEvents
  11.   Loop
  12.   If Not .Status = 200 Then Exit Sub   '←正常処理以外は終了させる
  13.   MsgBox .responseText
  14.  End With
  15.  Set XHR = Nothing
  16. End Sub
図18

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の文字列・内容は以下となります。
クラスstatusstatusText内容
情報100Continueリクエスト継続可能
101Switching Protocolsプロトコルを切り替え
102Processing処理中で、まだレスポンスを提供できない
103Early Hintsリソースの事前読み込み可
成功200OKリクエスト成功し、正常処理
201Createdリクエスト成功し、新たなリソースを作成
202Acceptedリクエスト受理したが、処理未
203Non-Authoritative Informationレスポンス情報が複製データ
204No Contentリクエストに対するコンテンツ無し。但しヘッダは有用。
205Reset Contentリクエストを送信した文章のリセットを指示
206Partial Content要求の内、一部分のみのリクエストが成功
リダイレクト300Multiple Choiceリクエストに対して複数のレスポンス有り
301Moved Permanently恒久的に移動
302Found一時的に移動
304Not Modified更新されていない(ブラウザキャッシュ使用)
クライアントエラ|400Bad Request一般的なクライアントエラー
401Unauthorizedアクセス権が無い、または認証に失敗
402Payment Required料金の支払いをするまでリクエストの処理不可
403Forbidden閲覧権限が無いファイルやフォルダ
404Not FoundWebページが見つからない
405Method Not Allowed送信するクライアント側のメソッドが許可されていない
406Not Acceptableサーバ側が受付不可能な値
407Proxy Authentication Requiredプロキシサーバの認証情報が不足
408Request Timeoutリクエスト送信後のやり取り時間が長く時間切れ
409Conflictサーバに既に存在しているデータが競合している
410Goneファイルが削除されWebページが存在しない
411Length RequiredContent-Lengthヘッダが無い
412Precondition Failedヘッダで定義された前提条件が満たされていない
413Payload Too Largeアップロードしたファイルの容量が上限を超えた
414URI Too Long指定したURLが長すぎる
415Unsupported Media Typeサーバで許可していないリクエストの種類
416Range Not Satisfiableサーバーがリクエストされた容量を提供できない
417Expectation Failedサーバが拡張されたステータスコードを返せない
422Unprocessable Entityリクエストは適正だが意味が異なる
423Lockedリクエスト内容がロックされている
425Too Earlyサーバが繰り返し処理が発生される可能性あり(≒無限ループ)
426Upgrade RequiredHTTP/1.1にアップグレードが必要
429Too Many Requests一定時間内にリクエスト数が多すぎる
431Request Header Fields Too Largeリクエストヘッダーが長すぎる
サ|バ|エラ|500Internal Server Error何らかのサーバ内で起きたエラー
501Not Implementedサーバーがリクエストに満たすのに必要な機能をサポートしていない
502Bad Gatewayゲートウェイ・プロキシサーバが不正なリクエストを受け取り拒否
503Service Unavailable一時的にサーバにアクセス出来ず
504Gateway Timeoutサーバからレスポンスがなくタイムアウト
505HTTP Version Not SupportedHTTPバージョンがサーバによってサポートされていない
506Variant Also NegotiatesURLを返すコンテンツで配置ミスなどによる内部サーバエラー
507Insufficient Storageサーバで処理するためのストレージ容量不足
508Loop Detected無限ループによりサーバーが操作終了
510Not Extendedアクセス集中によるエラー
511Network Authentication Requiredネットワーク認証要
尚、これ以外にもHTTPステータスコードは存在します。
図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値を使い、テキストファイルの内容を取得する事ができます。以下がコード例です。
  1. '========== ⇩(4) responseTextでテキストデータを取得 ============
  2. Sub test002()
  3.  Dim XHR As Object
  4. ' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_SJIS.txt"
  5. ' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF8N.txt"
  6. ' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF8B.txt"
  7. ' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16LEN.txt"
  8.  Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16LEB.txt"   '←UTF-16LE(BOM付)ファイル
  9. ' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16BEN.txt"
  10. ' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16BEB.txt"
  11.  Set XHR = CreateObject("MSXML2.ServerXMLHTTP.6.0")
  12.  With XHR
  13.   .Open "GET", FN, True
  14.   .send
  15.   Do Until .readyState = 4
  16.    DoEvents: DoEvents
  17.   Loop
  18.   If Not .Status = 200 Then Exit Sub
  19.   MsgBox .responseText
  20.  End With
  21.  Set XHR = Nothing
  22. End Sub
図20

84行目「.Open "GET", FN, True」でリクエストの準備を行い、85行目「.send」でリクエストを送信し、87~89行目のDo~Loopでレスポンスが届くのを待ちます。受け取ったレスポンス内のテキストデータをresponseTextプロパティを通して取得し、出力しているのが92行目「MsgBox .responseText」です。
アクセスしている先は73~79行目で、今回は全7種の文字コードの固定テキストファイルを準備しました(図15参照)。その文字コード別ファイルを使っての出力結果が以下です。
赤字で示した文字コードのテキストは正しく取得できるのですが、それ以外は正しく取得できない事がわかります。
responseTextでの文字コード別の出力例
図21

また図20で使用したオブジェクトは81行目「Set XHR = CreateObject("MSXML2.ServerXMLHTTP.6.0")」のようにServerXMLHTTPですが、それ以外にも図08図11のように多くのオブジェクトが使用できます。
この「生成オブジェクト × 文字コードファイル」で、正しいテキストデータが取得できるかを整理したのが以下になります。
なお表中の「事前」は事前バインディング、「実行時」は実行時バインディングで使用するオブジェクトを表しています。
生成オブジェクトS-JISUTF-8UTF-16LEUTF-16BE
BOM無BOM付BOM無BOM付BOM無BOM付

MSXML2ServerXMLHTTP×××
XMLHTTP×××
WinHttpWinHttpRequest×××××××


MSXML2ServerXMLHTTP×××
XMLHTTP×××
MicrosoftXMLHTTP×××
WinHttpWinHttpRequest.5.1×××××××
図22

まとめるとresponseTextプロパティで取得できる文字コードには制限があり、UTF-8 または UTF-16のBOM付で、且つWinHttp系以外のオブジェクトであれば、正しくデータが取得できるようです。
なお WinHttp系は、ASCII(英数字のみ)であれば問題なく取得できますが、半角カナ・漢字など日本語を含む文字コードには対応していないようです。もしWinHttp系のオブジェクトを使用する場合は、下で説明するresponseBodyプロパティを通してテキスト内容を取得する必要があります。

2-5.responseBody

responseBodyプロパティには、Web上のテキストデータの文字コードが「バイナリ値として配列の形」で入ります。配列のインデックスはゼロ始まりです。BOMが付いている場合はBOMもバイナリ値として入ってきます。
上で説明したresponseTextで文字化けしてしまう場合には、responseBodyプロパティを使用し文字コードに合った変換をする事で、テキストデータを得ることができます。
まず、バイナリデータを「String型に変換」して表示するサンプルコードが以下になります。
  1. '========== ⇩(5) UTF16LEのデータをresponseBodyで取得 ============
  2. Sub test003()
  3.  Dim XHR As Object
  4. ' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_SJIS.txt"
  5. ' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF8N.txt"
  6. ' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF8B.txt"
  7. ' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16LEN.txt"   '←UTF-16LE(BON無)ファイル
  8.  Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16LEB.txt"
  9. ' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16BEN.txt"
  10. ' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16BEB.txt"
  11.  Dim Str As String
  12.  Set XHR = CreateObject("MSXML2.serverXMLHTTP.6.0")
  13.  With XHR
  14.   .Open "GET", FN, True
  15.   .send
  16.   Do Until .readyState = 4
  17.    DoEvents: DoEvents
  18.   Loop
  19.   If Not .Status = 200 Then Exit Sub
  20.   Str = .responseBody
  21.   MsgBox Str
  22.  End With
  23.  Set XHR = Nothing
  24. End Sub
図23

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行目)を出力した結果が以下です。
responseBodyをString型に変換しての文字コード別の出力例
図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編」を参照下さい。
  1. '========== ⇩(6) UTF-16BEのデータをresponseBodyで取得 ============
  2. Sub test004()
  3.  Dim XHR As Object
  4.  Dim ADOst As Object
  5. ' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_SJIS.txt"
  6. ' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF8N.txt"
  7. ' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF8B.txt"
  8. ' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16LEN.txt"
  9. ' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16LEB.txt"
  10.  Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16BEN.txt"   '←UTF-16BEファイル
  11. ' Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16BEB.txt"
  12.  Dim Str As String
  13.  Set XHR = CreateObject("MSXML2.serverXMLHTTP.6.0")
  14.  With XHR
  15.   .Open "GET", FN, True
  16.   .send
  17.   Do Until .readyState = 4
  18.    DoEvents: DoEvents
  19.   Loop
  20.   If Not .Status = 200 Then Exit Sub
  21.   Set ADOst = CreateObject("ADODB.Stream")   '←ADODB.Streamオブジェクトの生成
  22.   ADOst.Open      '←Streamを開く
  23.    ADOst.type = 1   '←Streamをバイナリ型にする
  24.    ADOst.write .responseBody   '←Streamにレスポンスの配列データを入れる
  25.    ADOst.Position = 0   '←PositionをStreamの先頭に移動
  26.    ADOst.type = 2     '←Streamをテキスト型に変更
  27. '   ADOst.Charset = "Shift-JIS"
  28. '   ADOst.Charset = "UTF-8"
  29. '   ADOst.Charset = "unicode"
  30.    ADOst.Charset = "UTF-16BE"   '←Streamの文字コードをUTF-16BEにする
  31.    Str = ADOst.ReadText(-1)   '←Streamから全テキストデータを読み取る
  32.   ADOst.Close
  33.   Set ADOst = Nothing
  34.   MsgBox Str
  35.  End With
  36.  Set XHR = Nothing
  37. End Sub
図25

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プロパティに設定」すれば、以下のようにどの文字コードの場合にも正しく出力されます。
ADODB.Streamを使い、文字コード毎に変換した例
図26

なお、文字コードに対応しているCharset値は以下のようになりますが、詳細はADODB.Stream編の「Charsetの設定と文字コードとの関係表」を参照下さい。
Charset=Shift-JISUTF-8UTF-16LEUTF-16BE
BOM無BOM付BOM無BOM付BOM無BOM付
Shift-JIS
UTF-8
unicode(既定)
UTF-16BE
(△:先頭にBOM値が文字化けした?印が入る)
図27

なおShift-JISの場合には、ADODB.Streamでは無くVBAのStrConv関数を使って、以下のようなコードとしてもOKです。
  1. '========== ⇩(7) Shift-JISのデータをresponseBodyで取得 ============
  2. Sub test005()
  3.  Dim XHR As Object
  4.  Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_SJIS.txt"
  5.  Dim Str As String
  6.  Set XHR = CreateObject("MSXML2.serverXMLHTTP.6.0")
  7.  With XHR
  8.   .Open "GET", FN, True
  9.   .send
  10.   Do Until .readyState = 4
  11.    DoEvents: DoEvents
  12.   Loop
  13.   If Not .Status = 200 Then Exit Sub
  14.   Str = StrConv(.responseBody, vbUnicode)
  15.   MsgBox Str
  16.  End With
  17.  Set XHR = Nothing
  18. End Sub
図28

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>
図29

このXMLファイルを読み取り、出力するのが以下のコードです。
  1. '========== ⇩(9) XMLファイルを読み取る ============
  2. Sub test006()
  3.  Dim XHR As Object
  4.  Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_xml.xml"
  5.  Set XHR = CreateObject("MSXML2.XMLHTTP.6.0")
  6.  With XHR
  7.   .Open "GET", FN, True
  8.   .send
  9.   Do Until .readyState = 4
  10.    DoEvents: DoEvents
  11.   Loop
  12.   If Not .Status = 200 Then Exit Sub
  13.   MsgBox .responseXML.Text
  14.  End With
  15.  Set XHR = Nothing
  16. End Sub
図30

responseXMLプロパティはDOMDocumentオブジェクト型です。その下のTextプロパティにはテキストとしてデータが入っているので、266行「MsgBox .responseXML.Text」で取得し表示させています。メッセージ出力の様子は以下の様になります。
responseXMLで取得したデータの出力
図31

データである「みかん」と「130」の間には「SP(半角スペース)」が入った形ですが、これは図29の「<種類>みかん</種類>」と「<価格>130</価格>」の間に改行が入ったXMLファイルだからです。
もし「<種類>みかん</種類><価格>130</価格>」というように1行でデータセットが書かれていれば、「みかん」と「130」の間にはスペースが入らず連続したデータとして出力されますし、逆にタグとデータが下記のように行を変えて書かれていれば、SP(半角スペース)の両側にLf(改行)マークが入るようです。
  • '========== ⇩(10) XMLファイルの内容2 ============
  • <Data>
  • <果実>
  • <種類>
  • みかん
  • </種類>
  • <価格>
  • 130
  • </価格>
図32

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_
RevertImpersonationOverSsl
11取得/設定証明書認証操作の間、クライアントの偽装(承認状態)を一時的に元に戻すか否かTrue=一時的に元に戻す(既定)
WinHttpRequestOption_
EnableHttpsToHttpRedirects
12取得/設定HTTPSから HTTPへのリダイレクトを有効にするTrue=有効にする
False=無効(既定)
(HTTPS→HTTP以外のリダイレクト有効)
WinHttpRequestOption_
EnablePassportAuthentication
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_
EnableCertificateRevocationCheck
18取得/設定証明書失効チェックの有効化Falseが既定?
WinHttpRequestOption_
RejectUserpwd
19取得/設定パスワードを拒否?Falseが既定?
図33

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)無効な日付または有効期限切れ
図34

この機能は「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(既定)
図35

WinHttpRequestOption_SecureProtocols(値=9)は、セキュリティプロトコルの指定です。値は以下の内容との事です。
値 (カッコ内は10進数)プロトコル
0x0008(8)SSL 2.0
0x0020(32)SSL 3.0
0x0080(128)TLS 1.0
図36

Microsoftの説明では取得/設定が可能との事ですが、VBAで値取得するとエラーが発生します。つまりVBAでは設定のみのようです。取得不可のため、既定だと紹介されている値(0x0028:SSL2.0またはSSL3.0)も確認できません。
またゼロを指定すると「受け入れ可能なセキュリティプロトコルが決定できずエラーが発生」と他サイトでは説明していますが、VBAでゼロを設定しても特にエラーが出ることはありません。
値=10以降の内容は良く分かりませんし、他サイトでの情報もほとんどありませんので割愛します。
下記コードはOptionプロパティの全ての値(値=5と値=9は設定のみのため除外)を取得するものです。
  1. '========== ⇩(11) Optionプロパティで設定情報を取得 ============
  2. Sub test007()
  3.  Dim XHR As Object
  4.  Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16LEB.txt"
  5.  Dim Str As String
  6.  Dim i As Integer
  7.  Set XHR = CreateObject("Winhttp.winhttprequest.5.1")
  8.  With XHR
  9.   .Open "GET", FN, False
  10.   .send
  11.   If Not .Status = 200 Then Exit Sub
  12.   For i = 0 To 19
  13.    If Not (i = 5 Or i = 9) Then
  14.     Str = Str & i & vbTab & .Option(i) & vbCrLf
  15.    End If
  16.   Next i
  17.   MsgBox Str
  18.  End With
  19.  Set XHR = Nothing
  20. End Sub
図37

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」で文字列化の条件を追加しています。
出力された様子は以下です。
Optionプロパティでの情報取得
図38

3.XMLHTTPのメソッド

メソッドは15種ありますが、生成するオブジェクトの種類により使えるメソッドが決まっています。図09図12と内容が重複します。
メソッド事前バインディング実行時バインディング実行
位置
MSXML2WinHttpMSXML2MicrosoftWinHttp
ServerXMLHTTPXMLHTTPWinHttpRequestServerXMLHTTPXMLHTTPXMLHTTPWinHttpRequest.5.1
実行
open
send
abort bc
設定
setRequestHeader b
waitForResponse c
setTimeouts a
setProxy b
setOption a
setProxyCredentials b
setClientCertificateb
setCredentialsb
setAutoLogonPolicyb
取得
getAllResponseHeaders c
getResponseHeader c
getOption (a)bc
図39

15種のメソッドの内、メインは「Open」と「Send」ですが、その他のメソッドは以下のように「(a)Openの前」「(b)Openの後で且つSendの前」「(c)Sendの後」のどこで実行するかが決まっています。上表の右端列の"a・b・c"は、各メソッドを実行する位置を表しています。
  • '========== ⇩(12) メソッドの実行位置 ============
  •  (a)
  • Open ・・・
  •  (b)
  • Send ・・・
  •  (c)
図40

なお図39の一番下のgetOptionの引数に-1を指定した時はURLが戻されるのですが、Open前に実行するとその時点ではURLは指定されていないためエラーとなります。そのためOpen前の "a" はカッコ付きとしています。

3-1.open

openメソッドでは、通信の方法や送信先のURLを指定します。構文は以下です。
XMLHTTP.open(bstrMethod, bstrUrl ,[varAsync], [bstrUser], [bstrPassword])
5つある引数の内容は以下になります。
引数内容
1bstrMethod必須String通信方法(リクエストタイプ)
2bstrUrl必須Stringリクエストの送信先となるURL
3varAsync省略可BooleanTrue=非同期
False=同期(既定)
4bstrUser省略可String認証プロセスで使用するユーザー名
既定は""(長さゼロ文字列)
5bstrPassword省略可String認証プロセスで使用するパスワード
既定は""(長さゼロ文字列)
図41

第1引数(bstrMethod)には、通信方法(リクエストタイプ)を指定します。通信方法には、以下のように多くの種類があります。表の右列には、各通信方法でリクエストした時にファイル内容を取得できるか否かを示しています。
なお表内の「リソース」とは、クライアントが「サーバー側から受け取るデータ」と考えて下さい。
第一引数
(接続方法)
内容サーバー上のファイル
固定テキスト変動テキスト(PHP等)
GET法POST法
GETリソースをリクエストする×
POSTリソースに必要なデータを送信する
HEADヘッダ情報のみをリクエストする空データ空データ空データ
PUTリソースを全て変更405エラー×
PATCHリソースを部分的に変更405エラー×
DELETE指定したリソースを削除405エラー×
CONNECTサーバーとの間にトンネルを確立Send実行時にエラー
OPTIONSリソースの通信オプションを示す空データ×
TRACEリクエストをオウム返しに返す405エラー405エラー405エラー
LINKURLとリソースを結合する501エラー×
UNLINKLINKを解除する501エラー×
〇×等はhttpsサーバーでの結果です。httpサーバーの場合は異なる可能性があります。
図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)

MSXML2ServerXMLHTTP
XMLHTTP
WinHttpWinHttpRequest


MSXML2ServerXMLHTTP
XMLHTTP
MicrosoftXMLHTTP
WinHttpWinHttpRequest5.1
図43

第4引数(bstrUser)・第5引数(bstrPassword)は、認証のためのユーザー名およびパスワードのようです。

3-2.send

リクエストをサーバーに送信するのがsendメソッドです。構文は以下です。
XMLHTTP.send([varBody])
引数内容
1varBody省略可Stringリクエストとともに送信されるメッセージ本文
図44

引数(varBody)は、固定したテキストファイルを取得するだけなら省略(または Null を指定)でOKです。
一方、クライアント側からサーバー側にデータを送付する場合の内、POST法(メッセージボディにデータを載せる)を使用する時は引数(varBody)に文字列として渡す「データ」を指定します。詳細は「クライアント側からデータをサーバーに送付」で説明します。
なおSendでリクエストを送信した後、レスポンスのデータを待ちreadyStateプロパティ値が4の状態になってから次の行に制御が移るのが「同期」、レスポンスを待つこと無くすぐに次の行に制御が移るのが「非同期」です。
この同期・非同期を指定しているのが、Openメソッドの第3引数(同期=False、非同期=True)です。
上記のOpenメソッドとSendメソッドを使った、「Web上からテキストファイルを取得」する基本的なコードを示します。
  1. '========== ⇩(13) OpenとSendを使った基本的なコード ============
  2. Sub test008()
  3.  Dim XHR As Object
  4.  Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF8B.txt"
  5.  Set XHR = CreateObject("Microsoft.XMLHTTP")
  6.  With XHR
  7.   .Open "GET", FN, False
  8.   .send Null
  9.   MsgBox .ResponseText
  10.  End With
  11.  Set XHR = Nothing
  12. End Sub
図45

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つの引数には以下の内容を指定します。
引数内容
1bstrHeader必須Stringヘッダー名
2bstrValue必須String設定する値
図46

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キャッシュ機能設定(HTTP/1.0 はPragmaを使用)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
図47

なおsetRequestHeaderメソッドでクライアント側から設定可能なのは、上表の右端列の〇印の項目だけのようです(表に載せた以外の項目の中には、設定可能な項目も存在するようです)。
サーバー上の固定ファイル(テキストファイルやHTMLファイル)を扱うのであれば、setRequestHeaderメソッドによるヘッダの設定は不要で、通信上必要となる項目は自動的にヘッダ設定されます。
しかし「クライアント側からデータをサーバーに送付」の中で説明するPOST法で「メッセージボディにパラメータ(=データ)を添付」する場合には、その添付データの種類をContent-Typeに指定します。このデータの種類は「MIMEのメディアタイプ」と呼ばれているようです。
Content-Type内容
text/plainテキストファイル
text/htmlHTMLファイル
text/xmlXMLファイル
text/csvCSVファイル
text/cssCSSファイル
text/javascriptJavaScriptファイル
text/vbscriptVBScriptファイル
application/jsonJSONファイル
(例: {“email”:"xxxx",”id”:"YYYY"})
application/x-www-form-urlencodedキーと値が "="で結ばれた形でエンコード
キーと値は "&"で区切られる
(例:email=xxxx&id=YYYY)
application/x-httpd-cgiCGIスクリプト
application/mswordWord文書
application/pdfPDFファイル
application/zipZipファイル
image/jpegJPEGファイル(.jpg, .jpeg)
image/pngPNGファイル
image/gifGIFファイル
image/svg+xmlSVGファイル
video/mpegMPEGファイル(動画)
図48

setRequestHeaderメソッドを指定しない状態(=既定)では Content-Typeは「text/html」となっているようです。「POST法でクライアントデータを送信」で説明するPOST法では、データを「キー = 値」という形で送るのですが、既定状態(=無指定)ではPOST法によるデータとは認識してくれないようです。
ですのでPOST法でデータを渡す場合は、Content-typeに「application/x-www-form-urlencoded」の指定が必要となります
また応答速度の高速化やサーバーへの負担軽減という目的から、Web上のファイルを色々な場所で「キャッシュ」という形で一時保管している場合があります。ですので、サーバー上でファイルを書き換えた直後は、クライアント側には「書き換える前の古いファイル(=キャッシュ値)」が戻る場合があります。(時間が経てば、キャッシュも最新状態に更新されます)
この対策として、SetRequestHeadeメソッドを使う事で「キャッシュを無効にし、最新の実ファイルの内容を取得」することが出来ます。以下がそのコード例です。
  1. '========== ⇩(14) SetRequestHeaderメソッドで最新内容を取得 ============
  2. Sub test009()
  3.  Dim XHR As Object
  4.  Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF8B.txt"
  5.  Set XHR = CreateObject("Microsoft.XMLHTTP")
  6.  With XHR
  7.   .Open "GET", FN, False
  8.   .SetRequestHeader "Pragma", "no-cache"      '←HTTP/1.0用
  9.   .SetRequestHeader "Cache-Control", "no-cache"   '←HTTP/1.1用
  10.   .SetRequestHeader "If-Modified-Since", "Thu,01 Jun 1970 00:00:00 GMT"   '←IE用?
  11.   .send
  12.   MsgBox .ResponseText
  13.  End With
  14.  Set XHR = Nothing
  15. End Sub
図49

実ファイルを参照する方法には以下の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
引数には、以下の様にレスポンスを待つ「秒数」を指定します。
引数内容
1timeoutInSeconds省略可数値レスポンスを待つ時間(秒単位)
図50

引数の既定値は「-1(INFINITE:無限大)」なので、引数を指定しない場合はずっと待ち続けるようです。ですので既定のままだと、ちょっと危険かもしれません。
設定値のデータ型は明記されていませんが、LongLong型を超える値を指定してもエラーとはなりません。また、小数点のある値を指定してもエラーとはなりませんが、例えば 0.5を設定するとゼロと見なされるようで、Round関数のような偶数側に丸める方式になっているようです。
戻り値はBoolean型で、True・Falseの内容は以下の内容になります。
 ・True=指定時間内にレスポンスを受信した(ReadyStateが4になった)
 ・False=指定時間内にレスポンスが返らず、タイムアウトが発生した
Trueになると、指定した時間に達していなくても、waitForResponseメソッドの次の行に制御が移ります。
この様子を図にしたのが以下です。waitForResponseの次にResponseTextでデータを取得しています。
WaitForResponseの動作
図51

上図で青い太矢印が「waitForResponseメソッドで指定した秒数」としています。
Sendメソッドでリクエストがサーバーに向かって発信され、サーバーからはレスポンスが返ってきますが、waitForResponseメソッドで指定した秒数内でレスポンスが返ってくれば「次の行に制御が移行」し、左図のようにResponseText等でデータが取得できることになります。
しかし、通信環境やデータのサイズなどが原因でレスポンスが遅くなり、waitForResponseメソッドで指定した秒数内にレスポンスが返ってこなかった時には、右図のように制御が移った先のResponseTextを実行する段階で、ReadyStateが4になっていないためにエラーとなります。
なお、図51の左はwaitForResponseメソッドの戻り値はTrue、右はFalseとなるのですが、例えばURLが間違っていた等により正常にリクエストできなかった時にも「waitForResponseメソッドはTrueを戻し、次の行に制御が移る」事になります。その意味では戻り値のみで正常・異常を判断するのは危険であり、Stateプロパティ値を調べ正常か否かを調べる必要が出てきます。
またFalseになると、図51の右側のようにwaitForResponseメソッドの次の行に制御が移りますが、リクエストが中断する訳ではないので、Do~Loopなどで待機していればレスポンスを受け取る事が可能です。
waitForResponseメソッドを使ってレスポンスを待つコード例を以下に示します。
  1. '========== ⇩(15) waitForResponseメソッドでレスポンスを待つ ============
  2. Sub test010()
  3.  Dim XHR As Object
  4.  Const FN = "http://atsumitm.iobb.net/its/excel/" & "Test_UTF8N.txt"
  5.  Dim Res As Boolean
  6.  Set XHR = CreateObject("MSXML2.serverXMLHTTP.6.0")    '←server系またはWinHttp系が必要
  7.  With XHR
  8.   .Open "GET", FN, True    '←非同期
  9.   .send
  10.   Res = .WaitForResponse(10)    '←最大10秒間レスポンスを待つ
  11.   If Res = False Then
  12.    MsgBox "時間内にレスポンスを取得できませんでした。"
  13.    Exit Sub
  14.   End If
  15.   If Not .Status = 200 Then Exit Sub
  16.   MsgBox .responseText
  17.  End With
  18.  Set XHR = Nothing
  19. End Sub
図52

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時間
1resolveTimeout必須Longドメイン名の解決のTimeOut時間
(ホスト名をIPアドレスにマッピングする時間)
無し
2connectTimeout必須Longサーバーへの接続の確立のTimeOut時間
(ターゲットサーバとの通信ソケットを確立する時間)
60秒
3sendTimeout必須Longデータの送信のTimeOut時間
(リクエストデータ(もしあれば)の個々のパケットを通信ソケット上で ターゲットサーバーに送信する時間)
30秒
4receiveTimeout必須Long応答の受信のTimeOut時間
(ターゲットサーバーから応答データのパケットを受信する時間)
30秒
図53

ヘッダ項目Keep-Aliveの中に現れる「timeout」は「待機状態の接続を開いたままにしておく必要のある最小時間 (秒単位) 」なので、上表のどれにも該当しないようです。またKeep-Aliveの中の「Max」は「接続を閉じる前にこの接続で送信できるリクエストの最大数」なので時間では無く、単位は回数です。
既定のTimeOut時間は、どれも「こんなに長時間で良いの?」と思ってしまうような時間ですが、特に必要が無い限りは既定のまま(=設定しない)で良いと思われます。
なお、setTimeoutsメソッドを実行する場合は、openメソッドの前に実行する必要があります。

3-7.setProxy

setProxyメソッドは、プロキシの設定をします。構文は以下です。
XMLHTTP.setProxy(proxySetting, [varProxyServer], [varBypassList])
3つの引数の内容は以下になります。
引数内容
1proxySetting必須HTTPREQUEST_PROXY_SETTING
SXH_PROXY_SETTING
定数内容
HTTPREQUEST_PROXYSETTING_DEFAULT
SXH_PROXY_SET_DEFAULT
0既定のプロキシ設定
HTTPREQUEST_PROXYSETTING_PRECONFIG
SXH_PROXY_SET_PRECONFIG
0レジストリからプロキシ設定を取得
HTTPREQUEST_PROXYSETTING_DIRECT
SXH_PROXY_SET_DIRECT
1プロキシでは無くWebサーバーに直接アクセス
(プロキシサーバーが無い)
HTTPREQUEST_PROXYSETTING_PROXY
SXH_PROXY_SET_PROXY
2第2・第3引数の値を適用
2varProxyServer省略可Stringプロキシサーバー名のリスト
3varBypassList省略可Stringホスト名やIPアドレスのリスト
表内の「HTTPREQUEST_」で始まるものはWinHttp系、「SXH_PROXY_」で始まるものはMSXML2系のデータ型と定数。
図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つの引数の内容は以下になります。
引数内容
1option必須SERVERXMLHTTP_OPTION(図57設定する種類
2value必須Variant設定値
図56

このsetOptionメソッドの実行位置ですが、URL関係(第1引数が0または1)の場合は「Openより前に実行」することで有効となる事が確認できました。しかし、SSL関係(第1引数が値=2または3)の時は確認できていません。しかし同じメソッドですので、(たぶん)Openより前に実行することで有効になると思われます。
第1引数(option)の値は、以下(SERVERXMLHTTP_OPTION列挙型)の4つの中から選択します。
定数内容
SXH_OPTION_URL_CODEPAGE0URLの文字列をシングルバイト変換する時の文字コード
SXH_OPTION_ESCAPE_PERCENT_IN_URL1True=URL内の%文字をエスケープする
False=%文字はそのまま
SXH_OPTION_IGNORE_SERVER_SSL_CERT_ERROR_FLAGS2SSL証明書エラーのマスク設定
SXH_OPTION_SELECT_CLIENT_SSL_CERT3送信するクライアント証明書を設定
図57

第2引数(value)は、当然ながら第1引数にどれを指定するかで変わってきます。
まず第1引数に「SXH_OPTION_URL_CODEPAGE(値=0)」を指定した場合は、URLの文字コードとして以下の値を第2引数に指定します。
定数説明
CP_ACP0ANSI コードページ
CP_OEMCP1OEM コードページ
CP_MACCP2Macintosh コードページ
CP_THREAD_ACP3現在のスレッドの ANSI コードページ
CP_SYMBOL42シンボルコードページ
CP_UTF765000UTF-7 を使った変換
CP_UTF865001UTF-8 を使った変換(既定 ?)
-932SHIFT-JIS
-51932EUC-JP
-50220JIS.ISO-2022-JP
-50932自動選択
図58

URL内や、URLの後ろにパラメータとして付加した文字に「アルファベットや数字以外の文字」が入る場合には、この設定値が影響してきます。実際に全角文字が入ったもので試してみるとUTF-8(既定 ?)以外の設定では、ファイルまで辿り着かなかった(404エラー)り、パラメータが正しく渡らなかったりします。
なおこれは、WinHttp系のOptionプロパティに引数=2を指定したものと同機能のようです。
寄り道(URLの文字コード設定)
上記で、影響を受ける文字を「アルファベットや数字以外の文字」と説明しましたが、リクエストデータを見てみると全角文字だけでは無く "=" のような記号も影響を受けるようです。なので「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_CERT_IGNORE_UNKNOWN_CA256不明な認証局
SXH_SERVER_CERT_IGNORE_WRONG_USAGE512サブジェクト名のない証明書など、不正な形式の証明書。
SXH_SERVER_CERT_IGNORE_CERT_CN_INVALID4096訪問したホスト名とサーバーで使用されている証明書名が不一致。
SXH_SERVER_CERT_IGNORE_CERT_DATE_INVALID8192証明書の日付が無効、または有効期限切れ。
SXH_SERVER_CERT_IGNORE_ALL_SERVER_ERRORS13056すべての証明書のエラー(既定)
図59

既定は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つの引数の内容は以下です。
引数内容
1bstrUserName必須String認証されるユーザー名
2bstrPassword必須String認証されるユーザーのパスワード
図60

第1引数(bstrUserName)にはプロキシサーバーに入るためのユーザー名を、第二引数(bstrPassword)にはそのパスワードを指定します。
なおこれは、WinHttp系のsetCredentialsメソッドに第3引数=1を指定したものと同機能のようです。

3-10.setClientCertificate

setClientCertificateメソッドは、HTTPSサーバーに送信するクライアント証明書を設定します。構文は以下です。
XMLHTTP.SetClientCertificate(ClientCertificate As String)
引数には「クライアント証明書」を指定します。
引数内容
1ClientCertificate必須Stringクライアント証明書
図61

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つの引数の内容は以下になります。
引数内容
1UserName必須String認証のユーザー名
2Password必須String認証のパスワード
3Flags必須HTTPREQUEST_SETCREDENTIALS_FLAGS
定数内容
HTTPREQUEST_SETCREDENTIALS_FOR_SERVER0資格情報はWebサーバーに渡す
HTTPREQUEST_SETCREDENTIALS_FOR_PROXY1資格情報はプロキシに渡す
図62

Webサーバー側とプロキシサーバー側の両方について認証をしなければならない場合は、Webサーバー側・プロキシサーバー側と2回に分けてsetCredentialsメソッドを実行する必要があるようです。
なおこのメソッドの第3引数に値=1を指定したものは、ServerXMLHTTP系のsetProxyCredentialsメソッドと同機能のようです。

3-12.setAutoLogonPolicy

setAutoLogonPolicyメソッドは、自動ログオンポリシーを指定します。構文は以下です。
XMLHTTP.SetAutoLogonPolicy(AutoLogonPolicy)
引数(AutoLogonPolicy)は WinHttpRequestAutoLogonPolicy列挙型で、以下の3種から選択します。
定数内容
AutoLogonPolicy_Always0すべての要求に対し、既定の資格情報を使用して認証されたログオンが実行される
AutoLogonPolicy_OnlyIfBypassProxy1既定の資格情報を使用して認証されたログオンは、LAN上の要求に対してのみ実行される(既定)
AutoLogonPolicy_Never2認証は自動的には使用されない
図63

何度読み返しても、どのサーバーに対しての設定なのかも含めて、内容は良く分かりません。

3-13.getAllResponseHeaders

getAllResponseHeadersメソッドは、HTTPレスポンスに添付された全レスポンスヘッダーを文字列で返します。レスポンスヘッダ同士はvbCrLf(0x0D0A)で区切られます。構文は以下で、引数はありません。
XMLHTTP.getAllResponseHeaders() As String
レスポンスヘッダーには多くの種類がありますが、その一例が図47(「要求(リクエスト)」専用のヘッダ項目を除く)です。しかし全種類が戻る訳では無く、そのレスポンスヘッダの内「HTTPレスポンスに添付された項目のみ」が戻されます。
コード例が下記です。
  1. '========== ⇩(16) GetAllResponseHeadersでレスポンスヘッダ情報を取得 ============
  2. Sub test011()
  3.  Dim XHR As Object
  4.  Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF8B.txt"
  5.  Set XHR = CreateObject("MSXML2.XMLHTTP.6.0")
  6.  With XHR
  7.   .Open "GET", FN, True
  8.   .send
  9.   Do Until .readyState = 4
  10.    DoEvents: DoEvents
  11.   Loop
  12.   If Not .Status = 200 Then Exit Sub
  13.   MsgBox .GetAllResponseHeaders
  14.  End With
  15.  Set XHR = Nothing
  16. End Sub
図64

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
引数内容
1bstrHeader必須Stringヘッダー名
図66

例えばレスポンスデータの長さ(ヘッダー「content-length」)を取得するのが、以下のコードです。
  1. '========== ⇩(17) getResponseHeaderメソッドでヘッダ情報を読み取る ============
  2. Sub test012()
  3.  Dim XHR As Object
  4.  Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16LEB.txt"
  5.  Set XHR = CreateObject("MSXML2.XMLHTTP.6.0")
  6.  With XHR
  7.   .Open "GET", FN, True
  8.   .send
  9.   Do Until .readyState = 4
  10.    DoEvents: DoEvents
  11.   Loop
  12.   If Not .Status = 200 Then Exit Sub
  13.   MsgBox .GetResponseHeader("content-length")
  14.  End With
  15.  Set XHR = Nothing
  16. End Sub
図67

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_URL-1リソースのURL値
SXH_OPTION_URL_CODEPAGE0URLの文字列をシングルバイト変換する時の文字コード
SXH_OPTION_ESCAPE_PERCENT_IN_URL1True=RL内の%文字をエスケープする
False=%文字はそのまま
SXH_OPTION_IGNORE_SERVER_SSL_CERT_ERROR_FLAGS2SSL証明書エラーのマスク種類
SXH_OPTION_SELECT_CLIENT_SSL_CERT3送信するクライアント証明書
図68

上表は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情報を取得しています。
  1. '========== ⇩(18) getOptionメソッドでURL設定やSSL設定の情報を取得 ============
  2. Sub test013()
  3.  Dim XHR As Object
  4.  Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_UTF16LEB.txt"
  5.  Dim Str As String
  6.  Dim i As Integer
  7.  Set XHR = CreateObject("MSXML2.serverXMLHTTP.6.0")
  8.  With XHR
  9.   .Open "GET", FN, True
  10.   .send
  11.   Do Until .readyState = 4
  12.    DoEvents: DoEvents
  13.   Loop
  14.   If Not .Status = 200 Then Exit Sub
  15.   For i = -1 To 3
  16.    Str = Str & i & vbTab & .getOption(i) & vbCrLf
  17.   Next i
  18.   MsgBox Str
  19.  End With
  20.  Set XHR = Nothing
  21. End Sub
図69

529行目「Str = Str & i & vbTab & .getOption(i) & vbCrLf」では、getOptionメソッドを使って各情報を取得し、メッセージとして出力しています。その出力例が以下です。
getOptionで得た情報の例
図70

4.クライアント側からデータをサーバーに送付

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

GET法では、サーバーに渡すデータが「URLの後ろにパラメータとして付与」されます。この方法は、ブラウザのURLボックスの値をコピペさえすれば、クライアントの要求内容をサーバー側が処理した後のデータを「他の人にも配布可能」というメリットがあります。逆に、どんなデータを送ったのかがURL値で丸見えになる為、セキュリティ的には不利です。
一方POST法では、サーバーに渡すデータが「メッセージボディに書かれた状態」で送付されます。こちらはURLは不変のため「他の人には見られない状態でサーバーにデータを送付」することが出来、セキュリティ面で有利となります。

4-1.GET法でクライアントデータを送信

GET法でサーバーにデータを渡すには、以下のように「URLの後ろにパラメータとしてデータを添付」します。
ここではGET法でのキーg1に「Aアあ」という値を、またキーg2には「Bイい」という値を渡しています。
  1. '========== ⇩(19) GET法でデータを送信 ============
  2. Sub test014()
  3.  Dim XHR As Object
  4.  Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_HTML.php" & "?g1=Aアあ&g2=Bイい"
  5.  Set XHR = CreateObject("MSXML2.serverXMLHTTP.6.0")
  6.  With XHR
  7.   .Open "GET", FN, True
  8.   .send
  9.   Do Until .readyState = 4
  10.    DoEvents: DoEvents
  11.   Loop
  12.   If Not .Status = 200 Then Exit Sub
  13.   MsgBox .responseText
  14.  End With
  15.  Set XHR = Nothing
  16. End Sub
図72

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
  •  
  • (メッセージボディーは無し)
図73

先頭行のURLに続けて、クライアント側からのデータが添付されていることが分かります。
寄り道(HTTPリクエストの中身を確認する方法)
図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エえ」という値を渡しています。
  1. '========== ⇩(21) POST法でデータを送信 ============
  2. Sub test015()
  3.  Dim XHR As Object
  4.  Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_HTML.php"
  5.  Set XHR = CreateObject("MSXML2.serverXMLHTTP.6.0")
  6.  With XHR
  7.   .Open "POST", FN, True
  8.   .setRequestHeader "Content-type", "application/x-www-form-urlencoded"
  9.   .send "p1=Cウう&p2=Dエえ"
  10.   Do Until .readyState = 4
  11.    DoEvents: DoEvents
  12.   Loop
  13.   If Not .Status = 200 Then Exit Sub
  14.   MsgBox .responseText
  15.  End With
  16.  Set XHR = Nothing
  17. End Sub
図74

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エえ   '←メッセージボディー
図75

メッセージボディにクライアントデータが書き込まれるのと同時に、ヘッダーに「Content-Length(ボディーのデータの長さ)」が自動的に追加されているのが分かります。

4-3.クライアントデータを受け取ったサーバー側での処理

データを受け取って処理をする「Test_HTML.php」の方は、以下のような内容になっています。
  1. '========== ⇩(23) クライアントデータの処理例 ============
  2. GET1 :<?php
  3. print $_GET['g1'];
  4. ?>
  5. GET2 :<?php
  6. print $_GET['g2'];
  7. ?>
  8. POST1:<?php
  9. print $_POST['p1'];
  10. ?>
  11. POST2:<?php
  12. print $_POST['p2'];
  13. ?>
図76

このPHPファイルに、GET及びPOSTでデータを送った場合(図72及び図74)には、以下のようなメッセージが返ります。
GET及びPOSTでリクエストした時の戻り値
図77

なおPOSTでリクエストする際、Sendメソッドの引数にデータを指定し、且つ「URLの後ろ側にパラメータを追加」したのが以下のコードです。
  1. '========== ⇩(24) Readメソッドで指定文字数分を読み取る ============
  2. Sub test016()
  3.  Dim XHR As Object
  4.  Const FN = "https://atsumitm.iobb.net/its/excel/" & "Test_HTML.php" & "?g1=Aアあ&g2=Bイい"
  5.  Set XHR = CreateObject("MSXML2.serverXMLHTTP.6.0")
  6.  With XHR
  7.   .Open "POST", FN, True
  8.   .SetRequestHeader "Content-type", "application/x-www-form-urlencoded"
  9.   .send "&p1=Cウう&p2=Dエえ"
  10.   Do Until .readyState = 4
  11.    DoEvents: DoEvents
  12.   Loop
  13.   If Not .Status = 200 Then Exit Sub
  14.   MsgBox .ResponseText
  15.  End With
  16.  Set XHR = Nothing
  17. End Sub
図78

この場合、下図右側のように「URLに追加したパラメータ」+「Sendの引数で指定したパラメータ」の両方ともが戻されます。
しかしOpenの第1パラメータに、POSTの代わりに「GETを指定」した場合は、下図左側のように「URLに追加したパラメータ」のみが戻ります。
GET及びPOSTでリクエストした時の戻り値2
図79

アプリ実例・関連する項目

計算や検索を行うサイトからデータを取得する
自分専用の関数を作る
祝日を自動反映するカレンダー

サンプルファイル

今回、説明の中で紹介したコードは、以下のサンプルファイルの標準モジュール(Module1)に記載しています。実行するにはVBEから直接実行してください。
テキストファイルの読み取り_XMLHTTP編(its-052.xlsm)
セキュリティ向上を目的として「インターネット経由でダウンロードしたOfficeファイル(Excel等)のマクロは、既定でブロック」されるようにOfficeアプリケーションの既定動作が変更になりました。(2022年4月より切替開始)
解除の方法については「ダウンロードファイルのブロック解除方法」を参照下さい。