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