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