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 * setRequestPropertyでセットするデータを設定します。 350 * 351 * keys,vals各々、カンマ区切りで分解します。 352 * 353 * @og.rev 5.10.16.0 (2019/10/04) 追加 354 * 355 * @param keys パラメータキー(カンマ区切り) 356 * @param vals パラメータ(カンマ区切り) 357 */ 358 public void setRequestProperty( final String keys, final String vals ) { 359 if( keys != null && keys.length() > 0 && vals != null && vals.length() > 0 ){ 360 final String[] propKeys = StringUtil.csv2Array( keys ); 361 final String[] propVals = StringUtil.csv2Array( vals ); 362 363 if( propKeys.length == propVals.length && propKeys.length > 0 ) { 364 for( int i=0; i<propKeys.length; i++ ) { 365 addRequestProperty( propKeys[i], propVals[i] ); 366 } 367 } 368 else { 369 final String errMsg = "パラメータのキーと、値の数が一致しません。" + CR 370 + " key=[" + keys + "]" + CR 371 + " val=[" + vals + "]" ; 372 throw new IllegalArgumentException( errMsg ); 373 } 374 } 375 } 376 377 /** 378 * 指定のURLに対して、コネクトするのに使用するプロキシ設定を行います。 379 * このときに、ヘッダー情報を内部変数に設定しておきます。 380 * 381 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 382 * 383 * @param host 接続するプロキシのホスト名(nullの場合は、登録しません) 384 * @param port 接続するプロキシのポート番号 385 */ 386 public void setProxy( final String host,final int port ) { 387 if( !StringUtil.isNull( host ) ) { 388 proxy = new HttpHost( host , port ); 389 } 390 } 391 392 /** 393 * Header として、HttpClient にセットするデータを設定します。 394 * 395 * 例えばJSON形式でPOSTする場合は通常"Content-Type", "application/json"を指定します。 396 * 397 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 398 * 399 * @param key パラメータキー(nullの場合は、登録しません) 400 * @param val パラメータ値(nullの場合は、登録しません) 401 */ 402 public void addHeaderProperty( final String key, final String val ) { 403 if( !StringUtil.isNull( key ) && !StringUtil.isNull( val ) ) { 404 headers.add( new BasicHeader( key,val ) ); 405 } 406 } 407 408 /** 409 * URL接続先のバイナリファイルをダウンロード取得します。 410 * 411 * 取得したファイルは、dwldFile にバイナリのまま書き込まれます。 412 * よって、エンコードの指定は不要です。 413 * 414 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 415 * 416 * @param dwldFile ダウンロードするファイル名。 417 * @throws IOException 入出力エラーが発生したとき 418 */ 419 public void setDownloadFile( final String dwldFile ) throws IOException { 420 this.dwldFile = dwldFile; 421 } 422 423 /** 424 * URL接続先のバイナリファイルをアップロードします。 425 * 426 * 取得したファイルは、upldFile にバイナリのまま書き込まれます。 427 * よって、エンコードの指定は不要です。 428 * アップロード は、multipart/form-data で送信するため、isPost = true を 429 * 内部的に設定しておきます。 430 * 431 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 432 * 433 * @param upldFile アップロードするファイル名。 434 * @throws IOException 入出力エラーが発生したとき 435 */ 436 public void setUploadFile( final String upldFile ) throws IOException { 437 this.upldFile = upldFile; 438 isPost = true; 439 } 440 441 /** 442 * エンコード情報を設定します。 443 * 444 * 初期値は、UTF-8 です。 445 * 446 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 447 * 448 * @param chset エンコード情報(nullの場合は、初期値:UTF-8 になります) 449 */ 450 public void setCharset( final String chset ) { 451 if( !StringUtil.isNull( chset ) ) { 452 charset = chset; 453 } 454 } 455 456 /** 457 * 接続タイムアウト時間を(秒)で指定します 458 * 459 * 実際には、org.apache.http.client.config.RequestConfig に対して、 460 * .setConnectTimeout( timeout * 1000 ) 461 * .setSocketTimeout( timeout * 1000 ) 462 * のように、 1000倍して設定しています。 463 * 0 は、無限のタイムアウト、マイナスは、設定しません。(つまりJavaの初期値のまま) 464 * 465 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 466 * 467 * @param tout タイムアウト時間(秒) (ゼロは、無制限) 468 */ 469 public void setTimeout( final int tout ) { 470 timeout = tout; 471 } 472 473 /** 474 * trueの場合、POSTを使用して接続します(初期値:false)。 475 * 476 * 通常はGETですが、外部から強制的に、POSTで送信したい場合に、 477 * 設定します。 478 * ただし、バイナリファイルをアップロードか、URLの長さ制限が、 479 * {@value #MAX_GET_LENGTH} を超えた場合は、内部で自動的に、post にします。 480 * 481 * @og.rev 6.9.0.1 (2018/02/05) 新規作成 482 * 483 * @param usePost true:POST使用/false:通常(GET) 484 */ 485 public void usePost( final boolean usePost ) { 486 isPost = usePost; 487 } 488 489 /** 490 * trueの場合、適度にデバッグ用のメッセージを出力します(初期値:false)。 491 * 492 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 493 * 494 * @param isDebug true:デバッグ用のメッセージを出力/false:通常 495 */ 496 public void setDebug( final boolean isDebug ) { 497 this.isDebug = isDebug; 498 } 499 500 /** 501 * 実行結果のステータスコード 情報を取得します。 502 * 503 * 結果は、#readData() メソッドをコールしないと取れません。 504 * 未実行の場合は、-1 がセットされています。 505 * 506 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 507 * 508 * @return 結果コード 情報 509 * @see #readData() 510 */ 511 public int getCode() { return rpsCode; } 512 513 /** 514 * メッセージ 情報を取得します。 515 * 516 * 結果は、#readData() メソッドをコールしないと取れません。 517 * 未実行の場合は、null がセットされています。 518 * 519 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 520 * 521 * @return メッセージ 情報 522 */ 523 public String getMessage() { return rpsMessage; } 524 525 /** 526 * HttpURLConnection のレスポンスコードに対応するメッセージ文字列を返します。 527 * 528 * HttpURLConnection の getResponseCode() メソッドにより取得された、HTTPレスポンスコード 529 * に対応する文字列を返します。この文字列は、HttpURLConnection で定義された 530 * static 定数のコメントを、定義しています。 531 * 532 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 533 * 534 * @param code HTTPレスポンスコード 535 * 536 * @return レスポンスコードに対応する文字列 537 * @og.rtnNotNull 538 * @see HttpURLConnection#HTTP_ACCEPTED 539 */ 540 public static String code2Message( final int code ) { 541 final String msg ; 542 switch( code ) { 543 case 100 : msg = "100: 要求は続行可能です。" ; break; 544 case 101 : msg = "101: プロトコルを切り替えます。" ; break; 545 case HttpURLConnection.HTTP_OK : msg = "200: OK です。" ; break; 546 case HttpURLConnection.HTTP_CREATED : msg = "201: 作成されました。" ; break; 547 case HttpURLConnection.HTTP_ACCEPTED : msg = "202: 受け入れられました。" ; break; 548 case HttpURLConnection.HTTP_NOT_AUTHORITATIVE : msg = "203: 信頼できない情報です。" ; break; 549 case HttpURLConnection.HTTP_NO_CONTENT : msg = "204: コンテンツがありません。" ; break; 550 case HttpURLConnection.HTTP_RESET : msg = "205: コンテンツをリセットします。" ; break; 551 case HttpURLConnection.HTTP_PARTIAL : msg = "206: 部分的なコンテンツです。" ; break; 552 case HttpURLConnection.HTTP_MULT_CHOICE : msg = "300: 複数の選択肢があります。" ; break; 553 case HttpURLConnection.HTTP_MOVED_PERM : msg = "301: 永続的に移動されました。" ; break; 554 case HttpURLConnection.HTTP_MOVED_TEMP : msg = "302: 一時的なリダイレクト。" ; break; 555 case HttpURLConnection.HTTP_SEE_OTHER : msg = "303: ほかを参照してください。" ; break; 556 case HttpURLConnection.HTTP_NOT_MODIFIED : msg = "304: 変更されていません。" ; break; 557 case HttpURLConnection.HTTP_USE_PROXY : msg = "305: プロキシを使用します。" ; break; 558 case 306 : msg = "306: 仕様の拡張案です。" ; break; 559 case 307 : msg = "307: 一時的なリダイレクトです。" ; break; 560 case HttpURLConnection.HTTP_BAD_REQUEST : msg = "400: 不当な要求です。" ; break; 561 case HttpURLConnection.HTTP_UNAUTHORIZED : msg = "401: 認証されませんでした。" ; break; 562 case HttpURLConnection.HTTP_PAYMENT_REQUIRED : msg = "402: 支払いが必要です。" ; break; 563 case HttpURLConnection.HTTP_FORBIDDEN : msg = "403: 禁止されています。" ; break; 564 case HttpURLConnection.HTTP_NOT_FOUND : msg = "404: 見つかりませんでした。" ; break; 565 case HttpURLConnection.HTTP_BAD_METHOD : msg = "405: メソッドは許可されません。" ; break; 566 case HttpURLConnection.HTTP_NOT_ACCEPTABLE : msg = "406: 受け入れられません。" ; break; 567 case HttpURLConnection.HTTP_PROXY_AUTH : msg = "407: プロキシの認証が必要です。" ; break; 568 case HttpURLConnection.HTTP_CLIENT_TIMEOUT : msg = "408: 要求がタイムアウトしました。" ; break; 569 case HttpURLConnection.HTTP_CONFLICT : msg = "409: 重複しています。" ; break; 570 case HttpURLConnection.HTTP_GONE : msg = "410: 存在しません。" ; break; 571 case HttpURLConnection.HTTP_LENGTH_REQUIRED : msg = "411: 長さが必要です。" ; break; 572 case HttpURLConnection.HTTP_PRECON_FAILED : msg = "412: 前提条件が満たされていません。" ; break; 573 case HttpURLConnection.HTTP_ENTITY_TOO_LARGE : msg = "413: 要求のエンティティが大きすぎます。" ; break; 574 case HttpURLConnection.HTTP_REQ_TOO_LONG : msg = "414: 要求のURIが大きすぎます。" ; break; 575 case HttpURLConnection.HTTP_UNSUPPORTED_TYPE : msg = "415: サポートされないメディアタイプです。" ; break; 576 case 416 : msg = "416: 要求された範囲は不十分です。" ; break; 577 case 417 : msg = "417: 要求どおりの処理が不可能です。" ; break; 578 case HttpURLConnection.HTTP_INTERNAL_ERROR : msg = "500: 内部サーバエラーです。" ; break; 579 case HttpURLConnection.HTTP_NOT_IMPLEMENTED : msg = "501: 実装されていません。" ; break; 580 case HttpURLConnection.HTTP_BAD_GATEWAY : msg = "502: 誤ったゲートウェイです。" ; break; 581 case HttpURLConnection.HTTP_UNAVAILABLE : msg = "503: サービスが利用できません。" ; break; 582 case HttpURLConnection.HTTP_GATEWAY_TIMEOUT : msg = "504: ゲートウェイがタイムアウトしました。" ; break; 583 case HttpURLConnection.HTTP_VERSION : msg = "505: サポートされていないHTTPバージョンです。" ; break; 584 default : msg = code + ": 未定義" ; break; 585 } 586 return msg ; 587 } 588 589 /** 590 * サンプル実行用のメインメソッド 591 * 592 * <pre> 593 * Usage: java org.opengion.fukurou.util.HttpConnect [-post=キー:ファイル名] … url [user:passwd] 594 * args[A] : url URLを指定します。GETの場合、パラメータは ?KEY=VALです 595 * args[*] : [-param=key:value] POST/GET時のパラメータのキーと値を:で区切って指定します。(複数回指定可) 596 * args[*] : [-header=key:value] ヘッダーに設定するパラメータのキーと値を:で区切って指定します。(複数回指定可) 597 * args[*] : [-auth=user:pass] BASIC認証のエリアへのアクセス時のユーザーとパスワードを指定します 598 * args[*] : [-proxy=host:port] proxy を使用する場合のホストとポートを指定します。 599 * args[*] : [-timeout=3] 接続タイムアウト時間を(秒)で指定します(初期値:無指定) 600 * args[*] : [-encode=UTF-8] エンコードを指定します。(初期値は UTF-8) 601 * args[*] : [-out=ファイル名] 結果をファイルに出力します。初期値は標準出力です 602 * args[*] : [-download=ファイル名] ファイル名を指定して、ダウンロードします 603 * args[*] : [-upload=ファイル名] ファイル名を指定して、multipart/form-dataでファイルアップロードします 604 * args[*] : [-errEx=true/false] trueの場合、レスポンスコードが、4XX,5XX の時に RuntimeException を投げます(初期値:false) 605 * args[*] : [#・・・・] コメント引数。(BATファイル上に残しておきたいが、使用したくない場合など) 606 * args[*] : [-debug=true/false] trueの場合、適度にデバッグ用のメッセージを出力します(初期値:false) 607 * </pre> 608 * 609 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 610 * 611 * @param args コマンド引数配列 612 * @throws IOException 入出力エラーが発生したとき 613 */ 614 public static void main( final String[] args ) throws IOException { 615 if( args.length < 2 ) { 616 LogWriter.log( "Usage: java org.opengion.fukurou.util.HttpConnect [-data/-binary] … url" ); 617 LogWriter.log( " args[A] : url URLを指定します。GETの場合、パラメータは ?KEY=VALです" ); 618 LogWriter.log( " args[*] : [-param=key:value] POST/GET時のパラメータのキーと値を:で区切って指定します。(複数回指定可)" ); 619 LogWriter.log( " args[*] : [-header=key:value] ヘッダーに設定するパラメータのキーと値を:で区切って指定します。(複数回指定可)" ); 620 LogWriter.log( " args[*] : [-auth=user:pass] BASIC認証のエリアへのアクセス時のユーザーとパスワードを指定します" ); 621 LogWriter.log( " args[*] : [-proxy=host:port] proxy を使用する場合のホストとポートを指定します。" ); 622 LogWriter.log( " args[*] : [-timeout=3] 接続タイムアウト時間を(秒)で指定します(初期値:無指定)" ); 623 LogWriter.log( " args[*] : [-encode=UTF-8] エンコードを指定します。(初期値は UTF-8)" ); 624 LogWriter.log( " args[*] : [-out=ファイル名] 結果をファイルに出力します。初期値は標準出力です" ); 625 LogWriter.log( " args[*] : [-download=ファイル名] ファイル名を指定して、ダウンロードします" ); 626 LogWriter.log( " args[*] : [-upload=ファイル名] ファイル名を指定して、multipart/form-dataでファイルアップロードします" ); 627 LogWriter.log( " args[*] : [-errEx=true/false] trueの場合、レスポンスコードが、4XX,5XX の時に RuntimeException を投げます(初期値:false)" ); 628 LogWriter.log( " args[*] : [#・・・・] コメント引数。(BATファイル上に残しておきたいが、使用したくない場合など)" ); 629 LogWriter.log( " args[*] : [-debug=true/false] trueの場合、適度にデバッグ用のメッセージを出力します(初期値:false)" ); 630 return; 631 } 632 633 String urlStr = null ; 634 final List<String> paramKey = new ArrayList<>(); // パラメーターキー 635 final List<String> paramVal = new ArrayList<>(); // パラメーター値 636 final List<String> headerKey = new ArrayList<>(); // パラメーターキー 637 final List<String> headerVal = new ArrayList<>(); // パラメーター値 638 639 String userPass = null ; 640 String proxy = null ; 641 int timeout = -1 ; 642 String encode = DEFAULT_CHARSET ; 643 String outFile = null ; 644 String dwldFile = null ; 645 String upldFile = null ; 646 boolean isEx = false ; 647 boolean isDebug = false ; 648 boolean nonWriter = false ; 649 650// int code = -1; 651 652 for( final String arg : args ) { 653 if( arg.startsWith( "-param=" ) ) { 654 final String[] prm = StringUtil.csv2Array( arg.substring( "-param=".length() ) , '=' , 2 ); 655 paramKey.add( prm[0] ); 656 paramVal.add( prm[1] ); 657 } 658 else if( arg.startsWith( "-header=" ) ) { 659 final String[] prm = StringUtil.csv2Array( arg.substring( "-header=".length() ) , '=' , 2 ); 660 headerKey.add( prm[0] ); 661 headerVal.add( prm[1] ); 662 } 663 else if( arg.startsWith( "-auth=" ) ) { 664 userPass = arg.substring( "-auth=".length() ); 665 if( StringUtil.isNull( userPass ) ) { 666 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 667 } 668 } 669 else if( arg.startsWith( "-proxy=" ) ) { 670 proxy = arg.substring( "-proxy=".length() ); 671 if( StringUtil.isNull( proxy ) ) { 672 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 673 } 674 } 675 else if( arg.startsWith( "-timeout=" ) ) { 676 timeout = Integer.parseInt( arg.substring( "-timeout=".length() ) ); 677 } 678 else if( arg.startsWith( "-encode=" ) ) { 679 encode = arg.substring( "-encode=".length() ); 680 if( StringUtil.isNull( encode ) ) { 681 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 682 } 683 } 684 else if( arg.startsWith( "-out=" ) ) { 685 outFile = arg.substring( "-out=".length() ); 686 if( StringUtil.isNull( outFile ) ) { 687 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 688 } 689 else { 690 if( "null".equalsIgnoreCase( outFile ) || "none".equalsIgnoreCase( outFile ) ) { 691 outFile = null; 692 nonWriter = true; 693 } 694 } 695 } 696 else if( arg.startsWith( "-download=" ) ) { 697 dwldFile = arg.substring( "-download=".length() ); 698 if( StringUtil.isNull( dwldFile ) ) { 699 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 700 } 701 } 702 else if( arg.startsWith( "-upload=" ) ) { 703 upldFile = arg.substring( "-upload=".length() ); 704 if( StringUtil.isNull( upldFile ) ) { 705 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 706 } 707 } 708 else if( arg.startsWith( "-errEx=" ) ) { 709 isEx = "true".equalsIgnoreCase( arg.substring( "-errEx=".length() ) ); 710 } 711 else if( arg.startsWith( "-debug=" ) ) { 712 isDebug = "true".equalsIgnoreCase( arg.substring( "-debug=".length() ) ); 713 } 714 else if( StringUtil.startsChar( arg , '-' ) ) { // 引数が未定義(処理は継続させます。) 715 System.err.println( "Error Argment:" + arg ); 716 } 717 else if( StringUtil.startsChar( arg , '#' ) ) { // 引数がコメント 718 continue; 719 } 720 else { 721 urlStr = arg; 722 } 723 } 724 725 try { // try catch を入れます。 726 final HttpConnect conn = new HttpConnect( urlStr,userPass ); 727 conn.setDebug( isDebug ); // 最初に入れておけば、それ以降、有効になります。 728 729 for( int i=0; i<paramKey.size(); i++ ) { 730 conn.addRequestProperty( paramKey.get(i) , paramVal.get(i) ); 731 } 732 733 for( int i=0; i<headerKey.size(); i++ ) { 734 conn.addHeaderProperty( headerKey.get(i) , headerVal.get(i) ); 735 } 736 737 // 6.8.1.3 (2017/08/04) proxy の設定 738 if( !StringUtil.isNull( proxy ) ) { 739 final String[] prm = StringUtil.csv2Array( proxy , ':' , 2 ); 740 final String host = prm[0]; 741 final int port = Integer.parseInt( prm[1] ); 742 conn.setProxy( host , port ); 743 } 744 745 conn.setCharset( encode ); // encode 指定 746 conn.setTimeout( timeout ); // timeout属性追加 747 conn.setUploadFile( upldFile ); 748 conn.setDownloadFile( dwldFile ); 749 750 final String outData = conn.readData(); 751 752 try( final PrintWriter writer = StringUtil.isNull( outFile ) 753 ? FileUtil.getLogWriter( "System.out" ) 754 : FileUtil.getPrintWriter( new File( outFile ),encode ) ) { 755 if( !nonWriter ) { 756 writer.println( outData ); 757 } 758 final int code = conn.getCode(); 759 760 // isEx=trueの場合、レスポンスコードが、4XX,5XX の時に RuntimeException を投げます 761 if( code >= 400 ) { 762 final String errMsg = conn.getMessage(); 763 writer.println( errMsg ); 764 if( isEx ) { 765 throw new OgRuntimeException( errMsg ); 766 } 767 else { 768 System.exit( code ); 769 } 770 } 771 } 772 } 773 catch( final Throwable th ) { 774 throw new OgRuntimeException( th ); 775 } 776 } 777}