001/* 002 * Copyright (c) 2009 The openGion Project. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 013 * either express or implied. See the License for the specific language 014 * governing permissions and limitations under the License. 015 */ 016package org.opengion.fukurou.util; 017 018import java.io.File; 019import java.io.IOException; 020import java.io.PrintWriter; 021import java.net.HttpURLConnection; 022import java.net.MalformedURLException; 023import java.net.URL; 024import java.util.Arrays; 025import java.util.ArrayList; 026import java.util.List; 027import java.nio.file.Files; 028import java.nio.file.Paths; 029 // import java.nio.charset.Charset; 030import java.nio.charset.StandardCharsets; 031 032import org.apache.http.Header; 033import org.apache.http.HttpEntity; 034import org.apache.http.HttpHost; 035import org.apache.http.StatusLine; 036import org.apache.http.auth.AuthScope; 037import org.apache.http.auth.Credentials; 038import org.apache.http.auth.UsernamePasswordCredentials; 039import org.apache.http.client.config.RequestConfig; 040import org.apache.http.client.config.CookieSpecs; 041import org.apache.http.client.CredentialsProvider; 042import org.apache.http.client.entity.UrlEncodedFormEntity; 043import org.apache.http.client.methods.CloseableHttpResponse; 044import org.apache.http.client.methods.HttpGet; 045import org.apache.http.client.methods.HttpPost; 046import org.apache.http.client.methods.HttpUriRequest; 047import org.apache.http.entity.ContentType; 048import org.apache.http.entity.mime.MultipartEntityBuilder; 049import org.apache.http.entity.mime.HttpMultipartMode; 050import org.apache.http.impl.client.BasicCredentialsProvider; 051import org.apache.http.impl.client.CloseableHttpClient; 052import org.apache.http.impl.client.HttpClientBuilder; 053import org.apache.http.message.BasicHeader; 054import org.apache.http.message.BasicNameValuePair; 055import org.apache.http.NameValuePair; 056import org.apache.http.util.EntityUtils; 057 058// import org.opengion.fukurou.system.Closer; 059import org.opengion.fukurou.system.LogWriter; 060import org.opengion.fukurou.system.OgRuntimeException ; 061 062import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE; 063import static org.opengion.fukurou.system.HybsConst.CR; 064 065/** 066 * HttpConnect は、指定のURL にアクセスして、データを取得します。 067 * URL へのアクセスにより、エンジンでは各種処理を実行させることが可能になります。 068 * 例えば、帳票デーモンの起動や、長時間かかる処理の実行などです。 069 * なお、URLに引数が付く場合は、ダブルコーテーションで括って下さい。 070 * URL の指定は、先頭に何もつけませ。指定の順番も関係ありません。 071 * - 付き引数は、指定順番は、関係ありません。 072 * 先頭が # の引数は、コメントと判断します。 073 * 074 * <pre> 075 * Usage: java org.opengion.fukurou.util.HttpConnect [-post=キー:ファイル名] … url [user:passwd] 076 * args[A] : url URLを指定します。GETの場合、パラメータは ?KEY=VALです 077 * args[*] : [-param=key:value] POST/GET時のパラメータのキーと値を:で区切って指定します。(複数回指定可) 078 * args[*] : [-header=key:value] ヘッダーに設定するパラメータのキーと値を:で区切って指定します。(複数回指定可) 079 * args[*] : [-auth=user:pass] BASIC認証のエリアへのアクセス時のユーザーとパスワードを指定します 080 * args[*] : [-proxy=host:port] proxy を使用する場合のホストとポートを指定します。 081 * args[*] : [-timeout=3] 接続タイムアウト時間を(秒)で指定します(初期値:無指定) 082 * args[*] : [-encode=UTF-8] エンコードを指定します。(初期値は UTF-8) 083 * args[*] : [-out=ファイル名] 結果をファイルに出力します。初期値は標準出力です 084 * args[*] : [-download=ファイル名] ファイル名を指定して、ダウンロードします 085 * args[*] : [-upload=ファイル名] ファイル名を指定して、multipart/form-dataでファイルアップロードします 086 * args[*] : [-errEx=true/false] trueの場合、レスポンスコードが、4XX,5XX の時に RuntimeException を投げます(初期値:false) 087 * args[*] : [#・・・・] コメント引数。(BATファイル上に残しておきたいが、使用したくない場合など) 088 * args[*] : [-debug=true/false] trueの場合、適度にデバッグ用のメッセージを出力します(初期値:false) 089 * </pre> 090 * 091 * ※ URLConnect との違い。 092 * -info/-data 等の区別の廃止。(実質、-info がなくなる。) 093 * setDownloadFile(String) 追加(-binaryの代用) 094 * setUploadFile(String) 追加 095 * proxy 設定の変更 096 * 097 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 098 * 099 * @version 6.9.0.0 100 * @author Kazuhiko Hasegawa 101 * @since JDK8.0, 102 */ 103public class HttpConnect { 104 /** エンコードの初期値 {@value} */ 105 public static final String DEFAULT_CHARSET = "UTF-8" ; 106 /** 言語の初期値 {@value} */ 107 public static final String DEFAULT_LANG = "ja-JP" ; 108 /** User-Agentの初期値 {@value} */ 109 public static final String DEFAULT_AGENT = "openGion with Apache HttpClient" ; 110 /** GETで指定するときのURLの長さ制限 {@value} (IEの場合は、2,083文字) */ 111 public static final int MAX_GET_LENGTH = 2000 ; 112 113 private final String urlStr ; 114 private final String user ; 115 private final String pass ; 116 117 private int rpsCode = -1; 118 private String rpsMessage ; 119 private String charset = DEFAULT_CHARSET ; 120 private String upldFile ; 121 private String dwldFile ; // バイナリファイルとして受け取る場合のファイル名 122 private int timeout = -1; 123 private boolean isPost ; 124 private boolean isDebug ; 125 126 private HttpHost proxy ; 127 128 // 初期ヘッダー情報 129 private static final List<Header> INIT_HEADER = 130 Arrays.asList( 131 new BasicHeader( "Accept-Charset" , DEFAULT_CHARSET ) , 132 new BasicHeader( "Accept-Language" , DEFAULT_LANG ) , 133 new BasicHeader( "User-Agent" , DEFAULT_AGENT ) 134 ); 135 136 private final List<NameValuePair> reqParamList = new ArrayList<NameValuePair>(); // リクエストパラメーター(主にPOST時) 137 private final List<Header> headers = new ArrayList<>( INIT_HEADER ); // ヘッダーパラメーター 138 139 // GET でのパラメータのマージ。きちんとした方法がわかるまでの暫定処置 140 private final StringBuilder reqParamBuf = new StringBuilder( BUFFER_MIDDLE ); 141 142 /** 143 * 接続先URLと、認証用ユーザー:パスワードを指定する、コンストラクター 144 * 145 * 認証が必要ない場合は、userPass は、null でかまいません。 146 * 接続先URLは、HttpConnect で、urlEncode しますので、そのままの文字列でかまいません。 147 * 148 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 149 * 150 * @param url 接続するアドレスを指定します。(http://server:port/dir/file.html) 151 * @param userPass ユーザー:パスワード(認証接続が必要な場合) 152 */ 153 public HttpConnect( final String url, final String userPass ) { 154 urlStr = StringUtil.urlEncode2( url ); 155 156 if( StringUtil.isNull( userPass ) ) { 157 user = null; 158 pass = null; 159 } 160 else { 161 final String[] prm = StringUtil.csv2Array( userPass , ':' , 2 ); 162 user = prm[0]; 163 pass = prm[1]; 164 } 165 } 166 167 /** 168 * URL接続先のデータを取得します。 169 * 170 * この処理の前に、必要な情報を設定して置いてください。 171 * また、code や message は、このメソッドを実行しないと取得できませんのでご注意ください。 172 * 173 * 取得したデータは、指定のURL へのアクセスのみです。 174 * 通常のWebブラウザは、イメージや、JavaScriptファイル、CSSファイルなど、 175 * 各種ファイル毎にHTTP接続を行い、取得して、レンダリングします。 176 * このメソッドでの処理では、それらのファイル内に指定されているURLの 177 * 再帰的な取得は行いません。 178 * よって、フレーム処理なども行いません。 179 * 180 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 181 * 182 * @return 接続結果 183 * @og.rtnNotNull 184 * @throws IOException 入出力エラーが発生したとき 185 * @throws MalformedURLException URLの形式が間違っている場合 186 */ 187 public String readData() throws IOException , MalformedURLException { 188 HttpUriRequest method ; 189 if( isPost ) { 190 if( isDebug ) { System.out.println( "POST URL=" + urlStr ); } 191 method = new HttpPost( urlStr ); 192 193 if( !reqParamList.isEmpty() ) { 194 ((HttpPost)method).setEntity( new UrlEncodedFormEntity( reqParamList , DEFAULT_CHARSET ) ); 195 if( isDebug ) { reqParamList.forEach( v -> System.out.println( "PARAM KEY=" + v.getName() + " , VAL=" + v.getValue() ) ); } 196 } 197 198 if( !StringUtil.isNull( upldFile ) ) { 199 final File file = new File( upldFile ); 200 if( isDebug ) { System.out.println( " MULTI FILE=" + file ); } 201 final HttpEntity entity = MultipartEntityBuilder.create() 202 .setMode( HttpMultipartMode.BROWSER_COMPATIBLE ) 203 .setCharset( StandardCharsets.UTF_8 ) // ファイル名の文字化け対策 204 .addBinaryBody( "upload" , 205 file , 206 ContentType.DEFAULT_BINARY , 207 file.getName() ) 208 .build(); 209 ((HttpPost)method).setEntity( entity ); 210 } 211 } 212 else { 213 // GET でのパラメータのマージ。きちんとした方法がわかるまでの暫定処置 214 final String getStr = reqParamBuf.length() == 0 215 ? urlStr 216 : reqParamBuf.toString() ; 217 218 if( isDebug ) { System.out.println( "GET URL=" + getStr ); } 219 220 method = new HttpGet( getStr ); 221 } 222 223 String body = null; 224 try( CloseableHttpClient client = getClient() ; 225 CloseableHttpResponse response = client.execute(method) ) { 226 227 final StatusLine status = response.getStatusLine(); 228 final HttpEntity entity = response.getEntity(); 229 230 rpsCode = status.getStatusCode(); 231 rpsMessage = ( code2Message( rpsCode ) + CR + status.getReasonPhrase() ).trim(); 232 233 // バイナリファイルとして受け取る場合。正常時のみ処理します。 234 if( !StringUtil.isNull( dwldFile ) && rpsCode >= 200 && rpsCode < 300 ) { 235 Files.write( Paths.get( dwldFile ) , EntityUtils.toByteArray( entity ) ); 236 body = dwldFile; 237 } 238 else { 239 if( entity == null ) { 240 body = rpsMessage; // HttpEntity が受け取れなかった場合は、メッセージを表示します。 241 } 242 else { 243 body = EntityUtils.toString( entity, charset ); 244 } 245 } 246 } 247 248 return body; 249 } 250 251 /** 252 * 接続先の HttpClient オブジェクトを作成します。 253 * 254 * 接続に必要な情報を、設定します。 255 * CloseableHttpClient は、AutoCloseable を継承しています。 256 * 257 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 258 * 259 * @return HttpConnectionオブジェクト 260 * @throws IOException 入出力エラーが発生したとき 261 */ 262 private CloseableHttpClient getClient() throws MalformedURLException { 263 264 final HttpClientBuilder clBuild = HttpClientBuilder.create(); 265 266 // request configuration 267 final RequestConfig.Builder reqConfig = RequestConfig.custom() 268 .setCookieSpec( CookieSpecs.STANDARD ); // 最新のRFC準拠ヘッダーを理解するのが困難なので。 269 270 if( timeout >= 0 ) { 271 reqConfig.setConnectTimeout( timeout * 1000 ) // timeoutの単位は(秒)、設定値は、ミリ秒 272 .setSocketTimeout( timeout * 1000 ); 273 } 274 275 clBuild.setDefaultRequestConfig( reqConfig.build() ); 276 277 // headers (初期設定も入っているので、通常は、empty にはならない。) 278 if( !headers.isEmpty() ) { 279 clBuild.setDefaultHeaders( headers ); 280 } 281 282 // Auth 283 if( !StringUtil.isNull( user ) ) { 284 final URL url = new URL( urlStr ); 285 final AuthScope scope = new AuthScope( url.getHost(), url.getPort() ); 286 final Credentials cred = new UsernamePasswordCredentials( user ,pass ); 287 288 final CredentialsProvider credProvider = new BasicCredentialsProvider(); 289 credProvider.setCredentials( scope,cred ); 290 291 clBuild.setDefaultCredentialsProvider( credProvider ); 292 } 293 294 // Proxy 295 if( proxy != null ) { 296 clBuild.setProxy( proxy ); 297 } 298 299 // // (デフォルトのHttpClientは、最新のRFC準拠ヘッダーを理解するのが困難です。) 300 // // RequestConfig に、CookieSpecs.STANDARD を設定しているが、効果なければ、使わなくしてしまう。 301 // clBuild.disableCookieManagement(); 302 303 return clBuild.build(); // HttpClient httpClient = HttpClientBuilder.create().*****.build(); 304 } 305 306 /** 307 * 接続先に使用する引数(パラメータ)を追加します。 308 * 309 * これは、POSTでも、GETでも使用できます。 310 * POSTの場合は、NameValuePair として、HttpPost に、Entity としてセットするデータを設定します。 311 * GET の場合は、既存の接続先URLに、&キー=値・・・・ で、追記します。 312 * すでに、パラメータが指定済みの場合は、& で、そうでなければ、? で連結します。 313 * ここで指定するパラメータは、内部で、urlEncode しますので、そのままの文字列でかまいません。 314 * 315 * デフォルトは、GETですが、Internet Explorer では URL に最大 2,083 文字しか指定できないため、 316 * それ以上の場合は、POST に自動で切り替えます。 317 * 318 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 319 * 320 * @param key パラメータキー(nullの場合は、登録しません) 321 * @param val パラメータ値 322 */ 323 public void addRequestProperty( final String key, final String val ) { 324 if( !StringUtil.isNull( key ) ) { 325 reqParamList.add( new BasicNameValuePair( key,val ) ); // POST のときのパラメータ。(GETでも使えるはず?) 326 327 if( !isPost ) { // 明らかに、GET でない場合は、この処理を行わない。 328 if( reqParamBuf.length() == 0 ) { // 初めての場合 329 reqParamBuf.append( urlStr ) 330 .append( urlStr.indexOf( '?' ) > 0 ? '&' : '?' ) 331 .append( StringUtil.urlEncode2( key ) ) 332 .append( '=' ) 333 .append( StringUtil.urlEncode2( val ) ); // null のときは、長さゼロ文字列になる。 334 } 335 else if( reqParamBuf.length() > MAX_GET_LENGTH ) { 336 isPost = true; // GETで送れるURLの長さ制限を超えた場合は、POSTにする。 337 } 338 else { 339 reqParamBuf.append( '&' ) 340 .append( StringUtil.urlEncode2( key ) ) 341 .append( '=' ) 342 .append( StringUtil.urlEncode2( val ) ); // null のときは、長さゼロ文字列になる。 343 } 344 } 345 } 346 } 347 348 /** 349 * 指定のURLに対して、コネクトするのに使用するプロキシ設定を行います。 350 * このときに、ヘッダー情報を内部変数に設定しておきます。 351 * 352 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 353 * 354 * @param host 接続するプロキシのホスト名(nullの場合は、登録しません) 355 * @param port 接続するプロキシのポート番号 356 */ 357 public void setProxy( final String host,final int port ) { 358 if( !StringUtil.isNull( host ) ) { 359 proxy = new HttpHost( host , port ); 360 } 361 } 362 363 /** 364 * Header として、HttpClient にセットするデータを設定します。 365 * 366 * 例えばJSON形式でPOSTする場合は通常"Content-Type", "application/json"を指定します。 367 * 368 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 369 * 370 * @param key パラメータキー(nullの場合は、登録しません) 371 * @param val パラメータ値(nullの場合は、登録しません) 372 */ 373 public void addHeaderProperty( final String key, final String val ) { 374 if( !StringUtil.isNull( key ) && !StringUtil.isNull( val ) ) { 375 headers.add( new BasicHeader( key,val ) ); 376 } 377 } 378 379 /** 380 * URL接続先のバイナリファイルをダウンロード取得します。 381 * 382 * 取得したファイルは、dwldFile にバイナリのまま書き込まれます。 383 * よって、エンコードの指定は不要です。 384 * 385 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 386 * 387 * @param dwldFile ダウンロードするファイル名。 388 * @throws IOException 入出力エラーが発生したとき 389 */ 390 public void setDownloadFile( final String dwldFile ) throws IOException { 391 this.dwldFile = dwldFile; 392 } 393 394 /** 395 * URL接続先のバイナリファイルをアップロードします。 396 * 397 * 取得したファイルは、upldFile にバイナリのまま書き込まれます。 398 * よって、エンコードの指定は不要です。 399 * アップロード は、multipart/form-data で送信するため、isPost = true を 400 * 内部的に設定しておきます。 401 * 402 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 403 * 404 * @param upldFile アップロードするファイル名。 405 * @throws IOException 入出力エラーが発生したとき 406 */ 407 public void setUploadFile( final String upldFile ) throws IOException { 408 this.upldFile = upldFile; 409 isPost = true; 410 } 411 412 /** 413 * エンコード情報を設定します。 414 * 415 * 初期値は、UTF-8 です。 416 * 417 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 418 * 419 * @param chset エンコード情報(nullの場合は、初期値:UTF-8 になります) 420 */ 421 public void setCharset( final String chset ) { 422 if( !StringUtil.isNull( chset ) ) { 423 charset = chset; 424 } 425 } 426 427 /** 428 * 接続タイムアウト時間を(秒)で指定します 429 * 430 * 実際には、org.apache.http.client.config.RequestConfig に対して、 431 * .setConnectTimeout( timeout * 1000 ) 432 * .setSocketTimeout( timeout * 1000 ) 433 * のように、 1000倍して設定しています。 434 * 0 は、無限のタイムアウト、マイナスは、設定しません。(つまりJavaの初期値のまま) 435 * 436 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 437 * 438 * @param tout タイムアウト時間(秒) (ゼロは、無制限) 439 */ 440 public void setTimeout( final int tout ) { 441 timeout = tout; 442 } 443 444 /** 445 * trueの場合、POSTを使用して接続します(初期値:false)。 446 * 447 * 通常はGETですが、外部から強制的に、POSTで送信したい場合に、 448 * 設定します。 449 * ただし、バイナリファイルをアップロードか、URLの長さ制限が、 450 * {@value #MAX_GET_LENGTH} を超えた場合は、内部で自動的に、post にします。 451 * 452 * @og.rev 6.9.0.1 (2018/02/05) 新規作成 453 * 454 * @param usePost true:POST使用/false:通常(GET) 455 */ 456 public void usePost( final boolean usePost ) { 457 isPost = usePost; 458 } 459 460 /** 461 * trueの場合、適度にデバッグ用のメッセージを出力します(初期値:false)。 462 * 463 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 464 * 465 * @param isDebug true:デバッグ用のメッセージを出力/false:通常 466 */ 467 public void setDebug( final boolean isDebug ) { 468 this.isDebug = isDebug; 469 } 470 471 /** 472 * 実行結果のステータスコード 情報を取得します。 473 * 474 * 結果は、#readData() メソッドをコールしないと取れません。 475 * 未実行の場合は、-1 がセットされています。 476 * 477 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 478 * 479 * @return 結果コード 情報 480 * @see #readData() 481 */ 482 public int getCode() { return rpsCode; } 483 484 /** 485 * メッセージ 情報を取得します。 486 * 487 * 結果は、#readData() メソッドをコールしないと取れません。 488 * 未実行の場合は、null がセットされています。 489 * 490 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 491 * 492 * @return メッセージ 情報 493 */ 494 public String getMessage() { return rpsMessage; } 495 496 /** 497 * HttpURLConnection のレスポンスコードに対応するメッセージ文字列を返します。 498 * 499 * HttpURLConnection の getResponseCode() メソッドにより取得された、HTTPレスポンスコード 500 * に対応する文字列を返します。この文字列は、HttpURLConnection で定義された 501 * static 定数のコメントを、定義しています。 502 * 503 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 504 * 505 * @param code HTTPレスポンスコード 506 * 507 * @return レスポンスコードに対応する文字列 508 * @og.rtnNotNull 509 * @see HttpURLConnection#HTTP_ACCEPTED 510 */ 511 public static String code2Message( final int code ) { 512 final String msg ; 513 switch( code ) { 514 case 100 : msg = "100: 要求は続行可能です。" ; break; 515 case 101 : msg = "101: プロトコルを切り替えます。" ; break; 516 case HttpURLConnection.HTTP_OK : msg = "200: OK です。" ; break; 517 case HttpURLConnection.HTTP_CREATED : msg = "201: 作成されました。" ; break; 518 case HttpURLConnection.HTTP_ACCEPTED : msg = "202: 受け入れられました。" ; break; 519 case HttpURLConnection.HTTP_NOT_AUTHORITATIVE : msg = "203: 信頼できない情報です。" ; break; 520 case HttpURLConnection.HTTP_NO_CONTENT : msg = "204: コンテンツがありません。" ; break; 521 case HttpURLConnection.HTTP_RESET : msg = "205: コンテンツをリセットします。" ; break; 522 case HttpURLConnection.HTTP_PARTIAL : msg = "206: 部分的なコンテンツです。" ; break; 523 case HttpURLConnection.HTTP_MULT_CHOICE : msg = "300: 複数の選択肢があります。" ; break; 524 case HttpURLConnection.HTTP_MOVED_PERM : msg = "301: 永続的に移動されました。" ; break; 525 case HttpURLConnection.HTTP_MOVED_TEMP : msg = "302: 一時的なリダイレクト。" ; break; 526 case HttpURLConnection.HTTP_SEE_OTHER : msg = "303: ほかを参照してください。" ; break; 527 case HttpURLConnection.HTTP_NOT_MODIFIED : msg = "304: 変更されていません。" ; break; 528 case HttpURLConnection.HTTP_USE_PROXY : msg = "305: プロキシを使用します。" ; break; 529 case 306 : msg = "306: 仕様の拡張案です。" ; break; 530 case 307 : msg = "307: 一時的なリダイレクトです。" ; break; 531 case HttpURLConnection.HTTP_BAD_REQUEST : msg = "400: 不当な要求です。" ; break; 532 case HttpURLConnection.HTTP_UNAUTHORIZED : msg = "401: 認証されませんでした。" ; break; 533 case HttpURLConnection.HTTP_PAYMENT_REQUIRED : msg = "402: 支払いが必要です。" ; break; 534 case HttpURLConnection.HTTP_FORBIDDEN : msg = "403: 禁止されています。" ; break; 535 case HttpURLConnection.HTTP_NOT_FOUND : msg = "404: 見つかりませんでした。" ; break; 536 case HttpURLConnection.HTTP_BAD_METHOD : msg = "405: メソッドは許可されません。" ; break; 537 case HttpURLConnection.HTTP_NOT_ACCEPTABLE : msg = "406: 受け入れられません。" ; break; 538 case HttpURLConnection.HTTP_PROXY_AUTH : msg = "407: プロキシの認証が必要です。" ; break; 539 case HttpURLConnection.HTTP_CLIENT_TIMEOUT : msg = "408: 要求がタイムアウトしました。" ; break; 540 case HttpURLConnection.HTTP_CONFLICT : msg = "409: 重複しています。" ; break; 541 case HttpURLConnection.HTTP_GONE : msg = "410: 存在しません。" ; break; 542 case HttpURLConnection.HTTP_LENGTH_REQUIRED : msg = "411: 長さが必要です。" ; break; 543 case HttpURLConnection.HTTP_PRECON_FAILED : msg = "412: 前提条件が満たされていません。" ; break; 544 case HttpURLConnection.HTTP_ENTITY_TOO_LARGE : msg = "413: 要求のエンティティが大きすぎます。" ; break; 545 case HttpURLConnection.HTTP_REQ_TOO_LONG : msg = "414: 要求のURIが大きすぎます。" ; break; 546 case HttpURLConnection.HTTP_UNSUPPORTED_TYPE : msg = "415: サポートされないメディアタイプです。" ; break; 547 case 416 : msg = "416: 要求された範囲は不十分です。" ; break; 548 case 417 : msg = "417: 要求どおりの処理が不可能です。" ; break; 549 case HttpURLConnection.HTTP_INTERNAL_ERROR : msg = "500: 内部サーバエラーです。" ; break; 550 case HttpURLConnection.HTTP_NOT_IMPLEMENTED : msg = "501: 実装されていません。" ; break; 551 case HttpURLConnection.HTTP_BAD_GATEWAY : msg = "502: 誤ったゲートウェイです。" ; break; 552 case HttpURLConnection.HTTP_UNAVAILABLE : msg = "503: サービスが利用できません。" ; break; 553 case HttpURLConnection.HTTP_GATEWAY_TIMEOUT : msg = "504: ゲートウェイがタイムアウトしました。" ; break; 554 case HttpURLConnection.HTTP_VERSION : msg = "505: サポートされていないHTTPバージョンです。" ; break; 555 default : msg = code + ": 未定義" ; break; 556 } 557 return msg ; 558 } 559 560 /** 561 * サンプル実行用のメインメソッド 562 * 563 * <pre> 564 * Usage: java org.opengion.fukurou.util.HttpConnect [-post=キー:ファイル名] … url [user:passwd] 565 * args[A] : url URLを指定します。GETの場合、パラメータは ?KEY=VALです 566 * args[*] : [-param=key:value] POST/GET時のパラメータのキーと値を:で区切って指定します。(複数回指定可) 567 * args[*] : [-header=key:value] ヘッダーに設定するパラメータのキーと値を:で区切って指定します。(複数回指定可) 568 * args[*] : [-auth=user:pass] BASIC認証のエリアへのアクセス時のユーザーとパスワードを指定します 569 * args[*] : [-proxy=host:port] proxy を使用する場合のホストとポートを指定します。 570 * args[*] : [-timeout=3] 接続タイムアウト時間を(秒)で指定します(初期値:無指定) 571 * args[*] : [-encode=UTF-8] エンコードを指定します。(初期値は UTF-8) 572 * args[*] : [-out=ファイル名] 結果をファイルに出力します。初期値は標準出力です 573 * args[*] : [-download=ファイル名] ファイル名を指定して、ダウンロードします 574 * args[*] : [-upload=ファイル名] ファイル名を指定して、multipart/form-dataでファイルアップロードします 575 * args[*] : [-errEx=true/false] trueの場合、レスポンスコードが、4XX,5XX の時に RuntimeException を投げます(初期値:false) 576 * args[*] : [#・・・・] コメント引数。(BATファイル上に残しておきたいが、使用したくない場合など) 577 * args[*] : [-debug=true/false] trueの場合、適度にデバッグ用のメッセージを出力します(初期値:false) 578 * </pre> 579 * 580 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 581 * 582 * @param args コマンド引数配列 583 * @throws IOException 入出力エラーが発生したとき 584 */ 585 public static void main( final String[] args ) throws IOException { 586 if( args.length < 2 ) { 587 LogWriter.log( "Usage: java org.opengion.fukurou.util.HttpConnect [-data/-binary] … url" ); 588 LogWriter.log( " args[A] : url URLを指定します。GETの場合、パラメータは ?KEY=VALです" ); 589 LogWriter.log( " args[*] : [-param=key:value] POST/GET時のパラメータのキーと値を:で区切って指定します。(複数回指定可)" ); 590 LogWriter.log( " args[*] : [-header=key:value] ヘッダーに設定するパラメータのキーと値を:で区切って指定します。(複数回指定可)" ); 591 LogWriter.log( " args[*] : [-auth=user:pass] BASIC認証のエリアへのアクセス時のユーザーとパスワードを指定します" ); 592 LogWriter.log( " args[*] : [-proxy=host:port] proxy を使用する場合のホストとポートを指定します。" ); 593 LogWriter.log( " args[*] : [-timeout=3] 接続タイムアウト時間を(秒)で指定します(初期値:無指定)" ); 594 LogWriter.log( " args[*] : [-encode=UTF-8] エンコードを指定します。(初期値は UTF-8)" ); 595 LogWriter.log( " args[*] : [-out=ファイル名] 結果をファイルに出力します。初期値は標準出力です" ); 596 LogWriter.log( " args[*] : [-download=ファイル名] ファイル名を指定して、ダウンロードします" ); 597 LogWriter.log( " args[*] : [-upload=ファイル名] ファイル名を指定して、multipart/form-dataでファイルアップロードします" ); 598 LogWriter.log( " args[*] : [-errEx=true/false] trueの場合、レスポンスコードが、4XX,5XX の時に RuntimeException を投げます(初期値:false)" ); 599 LogWriter.log( " args[*] : [#・・・・] コメント引数。(BATファイル上に残しておきたいが、使用したくない場合など)" ); 600 LogWriter.log( " args[*] : [-debug=true/false] trueの場合、適度にデバッグ用のメッセージを出力します(初期値:false)" ); 601 return; 602 } 603 604 String urlStr = null ; 605 final List<String> paramKey = new ArrayList<>(); // パラメーターキー 606 final List<String> paramVal = new ArrayList<>(); // パラメーター値 607 final List<String> headerKey = new ArrayList<>(); // パラメーターキー 608 final List<String> headerVal = new ArrayList<>(); // パラメーター値 609 610 String userPass = null ; 611 String proxy = null ; 612 int timeout = -1 ; 613 String encode = DEFAULT_CHARSET ; 614 String outFile = null ; 615 String dwldFile = null ; 616 String upldFile = null ; 617 boolean isEx = false ; 618 boolean isDebug = false ; 619 boolean nonWriter = false ; 620 621// int code = -1; 622 623 for( final String arg : args ) { 624 if( arg.startsWith( "-param=" ) ) { 625 final String[] prm = StringUtil.csv2Array( arg.substring( "-param=".length() ) , '=' , 2 ); 626 paramKey.add( prm[0] ); 627 paramVal.add( prm[1] ); 628 } 629 else if( arg.startsWith( "-header=" ) ) { 630 final String[] prm = StringUtil.csv2Array( arg.substring( "-header=".length() ) , '=' , 2 ); 631 headerKey.add( prm[0] ); 632 headerVal.add( prm[1] ); 633 } 634 else if( arg.startsWith( "-auth=" ) ) { 635 userPass = arg.substring( "-auth=".length() ); 636 if( StringUtil.isNull( userPass ) ) { 637 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 638 } 639 } 640 else if( arg.startsWith( "-proxy=" ) ) { 641 proxy = arg.substring( "-proxy=".length() ); 642 if( StringUtil.isNull( proxy ) ) { 643 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 644 } 645 } 646 else if( arg.startsWith( "-timeout=" ) ) { 647 timeout = Integer.parseInt( arg.substring( "-timeout=".length() ) ); 648 } 649 else if( arg.startsWith( "-encode=" ) ) { 650 encode = arg.substring( "-encode=".length() ); 651 if( StringUtil.isNull( encode ) ) { 652 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 653 } 654 } 655 else if( arg.startsWith( "-out=" ) ) { 656 outFile = arg.substring( "-out=".length() ); 657 if( StringUtil.isNull( outFile ) ) { 658 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 659 } 660 else { 661 if( "null".equalsIgnoreCase( outFile ) || "none".equalsIgnoreCase( outFile ) ) { 662 outFile = null; 663 nonWriter = true; 664 } 665 } 666 } 667 else if( arg.startsWith( "-download=" ) ) { 668 dwldFile = arg.substring( "-download=".length() ); 669 if( StringUtil.isNull( dwldFile ) ) { 670 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 671 } 672 } 673 else if( arg.startsWith( "-upload=" ) ) { 674 upldFile = arg.substring( "-upload=".length() ); 675 if( StringUtil.isNull( upldFile ) ) { 676 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 677 } 678 } 679 else if( arg.startsWith( "-errEx=" ) ) { 680 isEx = "true".equalsIgnoreCase( arg.substring( "-errEx=".length() ) ); 681 } 682 else if( arg.startsWith( "-debug=" ) ) { 683 isDebug = "true".equalsIgnoreCase( arg.substring( "-debug=".length() ) ); 684 } 685 else if( StringUtil.startsChar( arg , '-' ) ) { // 引数が未定義(処理は継続させます。) 686 System.err.println( "Error Argment:" + arg ); 687 } 688 else if( StringUtil.startsChar( arg , '#' ) ) { // 引数がコメント 689 continue; 690 } 691 else { 692 urlStr = arg; 693 } 694 } 695 696 try { // try catch を入れます。 697 final HttpConnect conn = new HttpConnect( urlStr,userPass ); 698 conn.setDebug( isDebug ); // 最初に入れておけば、それ以降、有効になります。 699 700 for( int i=0; i<paramKey.size(); i++ ) { 701 conn.addRequestProperty( paramKey.get(i) , paramVal.get(i) ); 702 } 703 704 for( int i=0; i<headerKey.size(); i++ ) { 705 conn.addHeaderProperty( headerKey.get(i) , headerVal.get(i) ); 706 } 707 708 // 6.8.1.3 (2017/08/04) proxy の設定 709 if( !StringUtil.isNull( proxy ) ) { 710 final String[] prm = StringUtil.csv2Array( proxy , ':' , 2 ); 711 final String host = prm[0]; 712 final int port = Integer.parseInt( prm[1] ); 713 conn.setProxy( host , port ); 714 } 715 716 conn.setCharset( encode ); // encode 指定 717 conn.setTimeout( timeout ); // timeout属性追加 718 conn.setUploadFile( upldFile ); 719 conn.setDownloadFile( dwldFile ); 720 721 final String outData = conn.readData(); 722 723 try( final PrintWriter writer = StringUtil.isNull( outFile ) 724 ? FileUtil.getLogWriter( "System.out" ) 725 : FileUtil.getPrintWriter( new File( outFile ),encode ) ) { 726 if( !nonWriter ) { 727 writer.println( outData ); 728 } 729 final int code = conn.getCode(); 730 731 // isEx=trueの場合、レスポンスコードが、4XX,5XX の時に RuntimeException を投げます 732 if( code >= 400 ) { 733 final String errMsg = conn.getMessage(); 734 writer.println( errMsg ); 735 if( isEx ) { 736 throw new OgRuntimeException( errMsg ); 737 } 738 else { 739 System.exit( code ); 740 } 741 } 742 } 743 } 744 catch( final Throwable th ) { 745 throw new OgRuntimeException( th ); 746 } 747 } 748}