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; 031import java.util.concurrent.TimeUnit; // 8.0.0.0 (2021/07/31) Add 032 033// 8.0.0.0 (2021/07/31) httpclient-4.5.5.jar → httpclient5-5.1.jar 034// org.apache.http → org.apache.hc.core5.http or org.apache.hc.client5.http 035import org.apache.hc.core5.http.Header; 036import org.apache.hc.core5.http.HttpEntity; 037import org.apache.hc.core5.http.HttpHost; 038import org.apache.hc.core5.http.ClassicHttpRequest; 039import org.apache.hc.core5.http.ContentType; 040import org.apache.hc.core5.http.NameValuePair; 041import org.apache.hc.core5.http.ParseException; // 8.0.0.0 (2021/07/31) Add 042import org.apache.hc.core5.http.io.entity.EntityUtils; 043import org.apache.hc.core5.http.io.entity.StringEntity; 044import org.apache.hc.core5.http.io.support.ClassicRequestBuilder; 045import org.apache.hc.core5.http.message.BasicHeader; 046import org.apache.hc.core5.http.message.BasicNameValuePair; 047// import org.apache.hc.core5.http.message.StatusLine; // 8.0.0.0 (2021/07/31) Delete 048import org.apache.hc.client5.http.auth.AuthScope; 049import org.apache.hc.client5.http.auth.Credentials; 050import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; 051import org.apache.hc.client5.http.config.RequestConfig; 052// import org.apache.http.client.config.CookieSpecs; // 8.0.0.0 (2021/07/31) Delete 053// import org.apache.hc.client5.http.auth.CredentialsProvider; // 8.0.0.0 (2021/07/31) Delete 054import org.apache.hc.client5.http.entity.UrlEncodedFormEntity; 055import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder; 056// import org.apache.hc.client5.http.entity.mime.HttpMultipartMode; // 8.0.0.0 (2021/07/31) Delete 057import org.apache.hc.client5.http.classic.methods.HttpGet; 058import org.apache.hc.client5.http.classic.methods.HttpPost; 059//import org.apache.http.client.methods.HttpUriRequest; // 8.0.0.0 (2021/07/31) 060import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider; 061import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; 062import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; 063import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; 064// import org.apache.hc.client5.http.impl.cookie.BasicClientCookie; // 8.0.0.0 (2021/08/31) 065// import org.apache.hc.client5.http.cookie.Cookie; // 8.0.0.0 (2021/08/31) 066// import org.apache.hc.client5.http.impl.classic.HttpClients; 067// import org.apache.hc.client5.http.cookie.CookieStore; 068// import org.apache.http.impl.client.DefaultHttpClient;; 069import org.apache.hc.client5.http.cookie.BasicCookieStore; 070// import org.apache.hc.client5.http.cookie.Cookie; 071import org.apache.hc.client5.http.protocol.HttpClientContext; 072// import java.io.UnsupportedEncodingException; // 8.0.0.0 (2021/07/31) Delete 073 074import java.net.URI; 075import java.net.URISyntaxException; 076// import java.util.Calendar; // 8.0.0.0 (2021/08/31) 077import java.util.Map; 078// import java.util.Map.Entry; 079import java.util.HashMap; 080 081// import org.apache.http.impl.client.DefaultRedirectStrategy; 082// import org.apache.http.HttpRequest; 083// import org.apache.http.HttpResponse; 084// import org.apache.http.protocol.HttpContext; 085// import org.apache.http.ProtocolException; 086// import org.apache.http.impl.client.LaxRedirectStrategy; // 8.0.0.0 (2021/07/31) Delete 087 088// import org.opengion.fukurou.system.Closer; 089import org.opengion.fukurou.system.LogWriter; 090import org.opengion.fukurou.system.OgRuntimeException ; 091 092import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE; 093import static org.opengion.fukurou.system.HybsConst.CR; 094 095/** 096 * HttpConnect は、指定のURL にアクセスして、データを取得します。 097 * URL へのアクセスにより、エンジンでは各種処理を実行させることが可能になります。 098 * 例えば、帳票デーモンの起動や、長時間かかる処理の実行などです。 099 * なお、URLに引数が付く場合は、ダブルコーテーションで括って下さい。 100 * URL の指定は、先頭に何もつけませ。指定の順番も関係ありません。 101 * - 付き引数は、指定順番は、関係ありません。 102 * 先頭が # の引数は、コメントと判断します。 103 * 104 * <pre> 105 * Usage: java org.opengion.fukurou.util.HttpConnect [-post=キー:ファイル名] … url [user:passwd] 106 * args[A] : url URLを指定します。GETの場合、パラメータは ?KEY=VALです 107 * args[*] : [-param=key:value] POST/GET時のパラメータのキーと値を:で区切って指定します。(複数回指定可) 108 * args[*] : [-header=key:value] ヘッダーに設定するパラメータのキーと値を:で区切って指定します。(複数回指定可) 109 * args[*] : [-auth=user:pass] BASIC認証のエリアへのアクセス時のユーザーとパスワードを指定します 110 * args[*] : [-proxy=host:port] proxy を使用する場合のホストとポートを指定します。 111 * args[*] : [-timeout=3] 接続タイムアウト時間を(秒)で指定します(初期値:無指定) 112 * args[*] : [-encode=UTF-8] エンコードを指定します。(初期値は UTF-8) 113 * args[*] : [-out=ファイル名] 結果をファイルに出力します。初期値は標準出力です 114 * args[*] : [-download=ファイル名] ファイル名を指定して、ダウンロードします 115 * args[*] : [-upload=ファイル名] ファイル名を指定して、multipart/form-dataでファイルアップロードします 116 * args[*] : [-postRedirect=true] POST時に強制的にリダイレクトを行います(GET時は自動でリダイレクトします)(初期値:false) 7.2.5.0 (2020/06/01) 117 * args[*] : [-usePost=true] POSTを強制的に使用する場合にセットします(初期値:false) 118 * args[*] : [-errEx=true/false] trueの場合、レスポンスコードが、4XX,5XX の時に RuntimeException を投げます(初期値:false) 119 * args[*] : [-authJson=JSONコード] JSONコードで認証する場合に使用します。8.0.0.0 (2021/08/31) 120 * args[*] : [-authURL=認証用URL] JSONコードで認証するURLを指定します。8.0.0.0 (2021/08/31) 121 * args[*] : [-reqJson=JSONコード] パラメータをJSONで指定する場合に使用します。8.0.0.0 (2021/08/31) 122 * args[*] : [#・・・・] コメント引数。(BATファイル上に残しておきたいが、使用したくない場合など) 123 * args[*] : [-debug=true/false] trueの場合、適度にデバッグ用のメッセージを出力します(初期値:false) 124 * </pre> 125 * 126 * ※ URLConnect との違い。 127 * -info/-data 等の区別の廃止。(実質、-info がなくなる。) 128 * setDownloadFile(String) 追加(-binaryの代用) 129 * setUploadFile(String) 追加 130 * proxy 設定の変更 131 * 132 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 133 * @og.rev 8.0.0.0 (2021/08/31) httpclient5 対応 134 * 135 * https://hc.apache.org/httpcomponents-core-5.1.x/current/httpcore5/apidocs/ 136 * https://hc.apache.org/httpcomponents-client-5.1.x/current/httpclient5/apidocs/ 137 * 138 * @version 8.0.0.0 139 * @author Kazuhiko Hasegawa 140 * @since JDK11.0, 141 */ 142public class HttpConnect { 143 /** エンコードの初期値 {@value} */ 144 public static final String DEFAULT_CHARSET = "UTF-8" ; 145 /** 言語の初期値 {@value} */ 146 public static final String DEFAULT_LANG = "ja-JP" ; 147 /** User-Agentの初期値 {@value} */ 148 public static final String DEFAULT_AGENT = "openGion with Apache HttpClient" ; 149 /** GETで指定するときのURLの長さ制限 {@value} (IEの場合は、2,083文字) */ 150 public static final int MAX_GET_LENGTH = 2000 ; 151 152 private final String urlStr ; 153 private final String user ; 154 private final String pass ; 155 156 private final Map<String,String> jsonMap = new HashMap<>(); 157 158 private int rpsCode = -1; 159 private String rpsMessage ; 160 private String charset = DEFAULT_CHARSET ; 161 private String upldFile ; 162 private String dwldFile ; // バイナリファイルとして受け取る場合のファイル名 163 private int timeout = -1; 164 private boolean isPost ; 165 private boolean postRedirect ; // 7.2.5.0 (2020/06/01) postRedirect(POST時に強制的にリダイレクト) 166 private boolean isDebug ; 167 168 private String authJson ; // -authJson // 8.0.0.0 (2021/08/31) 169 private String authURL ; // -authURL // 8.0.0.0 (2021/08/31) 170 private String reqJson ; // -reqJson // 8.0.0.0 (2021/08/31) 171 172 private HttpHost proxy ; 173 174 // 初期ヘッダー情報 175 private static final List<Header> INIT_HEADER = 176 Arrays.asList( 177 new BasicHeader( "Accept-Charset" , DEFAULT_CHARSET ) , 178 new BasicHeader( "Accept-Language" , DEFAULT_LANG ) , 179 new BasicHeader( "User-Agent" , DEFAULT_AGENT ) 180 ); 181 182 private final List<NameValuePair> reqParamList = new ArrayList<NameValuePair>(); // リクエストパラメーター(主にPOST時) 183 private final List<Header> headers = new ArrayList<>( INIT_HEADER ); // ヘッダーパラメーター 184 185 // GET でのパラメータのマージ。きちんとした方法がわかるまでの暫定処置 186 private final StringBuilder reqParamBuf = new StringBuilder( BUFFER_MIDDLE ); 187 188 /** 189 * 接続先URLと、認証用ユーザー:パスワードを指定する、コンストラクター 190 * 191 * 認証が必要ない場合は、userPass は、null でかまいません。 192 * 接続先URLは、HttpConnect で、urlEncode しますので、そのままの文字列でかまいません。 193 * 194 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 195 * @og.rev 8.0.0.0 (2021/07/31) httpclient4 → httpclient5 対応 196 * 197 * @param url 接続するアドレスを指定します。(http://server:port/dir/file.html) 198 * @param userPass ユーザー:パスワード(認証接続が必要な場合) 199 */ 200 public HttpConnect( final String url, final String userPass ) { 201 urlStr = StringUtil.urlEncode2( url ); 202 203 if( StringUtil.isNull( userPass ) ) { 204 user = null; 205 pass = null; 206 } 207 else { 208 final String[] prm = StringUtil.csv2Array( userPass , ':' , 2 ); 209 user = prm[0]; 210 pass = prm[1]; 211 } 212 } 213 214// /** 215// * Form認証でのログイン 216// * 217// * https://hc.apache.org/httpcomponents-client-5.1.x/examples.html 218// * https://github.com/apache/httpcomponents-client/blob/5.1.x/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientFormLogin.java 219// * 220// * @og.rev 8.0.0.0 (2021/07/31) httpclient4 → httpclient5 対応 221// */ 222// private String formLogin() { 223// String body = null; 224// String secCheckURL = null; 225// 226// final BasicCookieStore cookieStore = new BasicCookieStore(); 227// try (final CloseableHttpClient httpclient = HttpClients.custom() 228// .setDefaultCookieStore(cookieStore) 229// .build()) { 230//// final HttpGet httpget = new HttpGet(urlStr); 231// final URI uri = new URI(urlStr); // j_security_check のアドレスを取るために。 232// final HttpGet httpget = new HttpGet(uri); 233// 234// try (final CloseableHttpResponse response1 = httpclient.execute(httpget)) { 235// final HttpEntity entity = response1.getEntity(); 236// 237// System.out.println("Login form get: " + response1.getCode() + " " + response1.getReasonPhrase()); 238// final String loginBody = EntityUtils.toString( entity, charset ); 239// // 一旦Form認証画面のHTMLが返ってくるので、その中から j_security_check を探してくる。 240// final int ed = loginBody.indexOf( "j_security_check" ); 241// if( ed >= 0 ) { 242// final int st = loginBody.lastIndexOf( '"',ed ); // 逆順に探す。 243// if( st >= 0 ) { 244// secCheckURL = uri.getScheme() + "://" + uri.getHost() + ':' + uri.getPort() 245// + loginBody.substring( st+1,ed ) + "j_security_check" ; 246// System.out.println(secCheckURL); 247// } 248// } 249// 250// EntityUtils.consume(entity); // リソースを解放 251// 252// // System.out.println("Initial set of cookies:"); 253// // final List<Cookie> cookies = cookieStore.getCookies(); 254// // if (cookies.isEmpty()) { 255// // System.out.println("None"); 256// // } else { 257// // for (int i = 0; i < cookies.size(); i++) { 258// // System.out.println("- " + cookies.get(i)); 259// // } 260// // } 261// } 262// 263// final ClassicHttpRequest login = ClassicRequestBuilder.post() 264// // .setUri(new URI("http://localhost:8828/gf/jsp/j_security_check")) 265// .setUri(new URI( secCheckURL )) 266// .addParameter("j_username", user) 267// .addParameter("j_password", pass) 268// .addParameter("j_security_check", "login") 269// .build(); 270// try (final CloseableHttpResponse response2 = httpclient.execute(login)) { 271// final HttpEntity entity = response2.getEntity(); 272// 273// System.out.println("Login form get: " + response2.getCode() + " " + response2.getReasonPhrase()); 274// body = EntityUtils.toString( entity, charset ); 275// 276// EntityUtils.consume(entity); // リソースを解放 277// 278// // System.out.println("Post logon cookies:"); 279// // final List<Cookie> cookies = cookieStore.getCookies(); 280// // if (cookies.isEmpty()) { 281// // System.out.println("None"); 282// // } else { 283// // for (int i = 0; i < cookies.size(); i++) { 284// // System.out.println("- " + cookies.get(i)); 285// // } 286// // } 287// } 288// } 289// catch( IOException ex ) { ex.printStackTrace(); } 290// catch( URISyntaxException ex ) { ex.printStackTrace(); } 291// catch( final ParseException ex ) {ex.printStackTrace();} 292// 293// return body ; 294// } 295 296 /** 297 * Form認証でのログイン 298 * 299 * https://hc.apache.org/httpcomponents-client-5.1.x/examples.html 300 * https://github.com/apache/httpcomponents-client/blob/5.1.x/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientFormLogin.java 301 * 302 * @og.rev 8.0.0.0 (2021/07/31) httpclient4 → httpclient5 対応 303 */ 304 private String formLogin( final CloseableHttpClient client , final URI uri ) { 305 String body = null; 306 307 try { 308 final URI secCheckURI = uri.resolve( "j_security_check" ); 309 if( isDebug ) { System.out.println( "security URI=" + secCheckURI ); } 310 311 final ClassicHttpRequest login = ClassicRequestBuilder.post() 312 // .setUri(new URI("http://localhost:8828/gf/jsp/j_security_check")) 313 .setUri( secCheckURI ) 314 .addParameter("j_username", user) 315 .addParameter("j_password", pass) 316 .addParameter("j_security_check", "login") 317 .build(); 318 319 try( CloseableHttpResponse response = client.execute(login) ) { 320 final HttpEntity entity = response.getEntity(); 321 322 rpsCode = response.getCode(); // 8.0.0.0 (2021/07/31) 323 rpsMessage = code2Message( rpsCode ).trim(); // 8.0.0.0 (2021/07/31) 324 325 // Form認証の場合、バイナリ処理は、formLogin 内で行います。 326 // バイナリファイルとして受け取る場合。成功(200番台)のみ処理します。 327 if( !StringUtil.isNull( dwldFile ) && rpsCode >= 200 && rpsCode < 300 ) { 328 Files.write( Paths.get( dwldFile ) , EntityUtils.toByteArray( entity ) ); 329 body = dwldFile; 330 } 331 else { 332 body = EntityUtils.toString( entity, charset ); 333 } 334 EntityUtils.consume(entity); // リソースを解放 335 } 336 } 337 catch( final IOException | ParseException ex ) { 338 throw new OgRuntimeException( ex ); 339 } 340 341 return body ; 342 } 343 344 /** 345 * 特別版ログイン 346 * 347 * @og.rev 8.0.0.0 (2021/08/31) httpclient4 → httpclient5 対応 348 * @og.rev 8.0.2.0 (2021/11/30) PMD:Avoid instantiating new objects inside loops 349 */ 350 private String jsonLogin( final CloseableHttpClient client ) { 351 String body = null; 352 353 try { 354 final ClassicHttpRequest login = new HttpPost( authURL ); 355 356 // 8.0.0.0 (2021/08/31) 357 login.setHeader("Content-type", "application/json"); 358 final HttpEntity stringEntity = new StringEntity(authJson,ContentType.APPLICATION_JSON); 359 login.setEntity( stringEntity ); 360 361 try( CloseableHttpResponse response = client.execute(login) ) { 362 final HttpEntity entity = response.getEntity(); 363 364 rpsCode = response.getCode(); // 8.0.0.0 (2021/07/31) 365 rpsMessage = code2Message( rpsCode ).trim(); // 8.0.0.0 (2021/07/31) 366 if( isDebug ) { System.out.println( "jsonLogin=" + rpsCode ); } 367 368 body = EntityUtils.toString( entity, charset ); 369 370 if( isDebug ) { System.out.println( "Login=" + body ); } 371 372 // ログイン時のリターンJSONから、パラメータを取得するMapを作成します。 373 if( !jsonMap.isEmpty() ) { 374 final StringBuilder buf = new StringBuilder(); // 8.0.2.0 (2021/11/30) 375 for( final String key : jsonMap.keySet() ) { 376 final int st = body.indexOf( key ); 377 if( st >= 0 ) { 378 final int ed = body.indexOf( ',',st+key.length() ); 379// final StringBuilder buf = new StringBuilder(); 380 buf.setLength(0); // 8.0.2.0 (2021/11/30) StringBuilder の初期化 381 if( ed > 0 ) { 382 for( int i=st+key.length(); i<ed; i++ ) { 383 final char ch = body.charAt(i); 384 if( ch != '"' && ch != ':' && ch != ' ' ) { 385 buf.append( ch ); 386 } 387 } 388 } 389 jsonMap.put( key,buf.toString() ); 390 if( isDebug ) { System.out.println( "Map=" + key + ":" + buf.toString() ); } 391 } 392 } 393 } 394 395 EntityUtils.consume(entity); // リソースを解放 396 } 397 } 398 catch( final IOException | ParseException ex ) { 399 throw new OgRuntimeException( ex ); 400 } 401 402 return body ; 403 } 404 405 /** 406 * 特別版ログイン 407 * 408 * @og.rev 8.0.0.0 (2021/08/31) httpclient4 → httpclient5 対応 409 */ 410 private String jsonDataget( final CloseableHttpClient client , final URI uri ) { 411 String body = null; 412 413 try { 414 final ClassicHttpRequest httpReq ; 415 416 if( reqJson == null ) { 417 httpReq = new HttpGet( uri ); // public/html/reportMain.html の時 418 } 419 else { 420 httpReq = new HttpPost( uri ); 421 httpReq.setHeader("Content-type", "application/json"); 422 423 String tempJson = reqJson; 424 if( !jsonMap.isEmpty() ) { 425 for( final Map.Entry<String,String> entry : jsonMap.entrySet() ) { 426 tempJson = tempJson.replace( '$'+entry.getKey()+'$' , entry.getValue() ); 427 } 428 } 429 430 if( isDebug ) { System.out.println( "reqJson=" + tempJson ); } 431 432 final HttpEntity stringEntity = new StringEntity(tempJson,ContentType.APPLICATION_JSON); 433 httpReq.setEntity( stringEntity ); 434 } 435 436 try( CloseableHttpResponse response = client.execute(httpReq) ) { 437 final HttpEntity entity = response.getEntity(); 438 439 rpsCode = response.getCode(); // 8.0.0.0 (2021/07/31) 440 rpsMessage = code2Message( rpsCode ).trim(); // 8.0.0.0 (2021/07/31) 441 if( isDebug ) { System.out.println( "jsonDataget=" + rpsCode ); } 442 443 body = EntityUtils.toString( entity, charset ); 444 EntityUtils.consume(entity); // リソースを解放 445 } 446 } 447 catch( final IOException | ParseException ex ) { 448 throw new OgRuntimeException( ex ); 449 } 450 451 return body ; 452 } 453 454 /** 455 * URL接続先のデータを取得します。 456 * 457 * この処理の前に、必要な情報を設定して置いてください。 458 * また、code や message は、このメソッドを実行しないと取得できませんのでご注意ください。 459 * 460 * 取得したデータは、指定のURL へのアクセスのみです。 461 * 通常のWebブラウザは、イメージや、JavaScriptファイル、CSSファイルなど、 462 * 各種ファイル毎にHTTP接続を行い、取得して、レンダリングします。 463 * このメソッドでの処理では、それらのファイル内に指定されているURLの 464 * 再帰的な取得は行いません。 465 * よって、フレーム処理なども行いません。 466 * 467 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 468 * @og.rev 8.0.0.0 (2021/07/31) httpclient4 → httpclient5 対応 469 * 470 * @return 接続結果 471 * @og.rtnNotNull 472 * @throws IOException 入出力エラーが発生したとき 473 * @throws MalformedURLException URLの形式が間違っている場合 474 */ 475 public String readData() throws IOException , MalformedURLException { 476 final ClassicHttpRequest method ; // 8.0.0.0 (2021/07/31) 477 if( isPost ) { 478 if( isDebug ) { System.out.println( "POST URL=" + urlStr ); } 479 method = new HttpPost( urlStr ); 480 481 if( !reqParamList.isEmpty() ) { 482 method.setEntity( new UrlEncodedFormEntity( reqParamList ) ); // 8.0.0.0 (2021/07/31) 483 if( isDebug ) { reqParamList.forEach( v -> System.out.println( "PARAM KEY=" + v.getName() + " , VAL=" + v.getValue() ) ); } 484 } 485 486 if( !StringUtil.isNull( upldFile ) ) { 487 final File file = new File( upldFile ); 488 if( isDebug ) { System.out.println( " MULTI FILE=" + file ); } 489 final HttpEntity entity = MultipartEntityBuilder.create() 490 .setCharset( StandardCharsets.UTF_8 ) // ファイル名の文字化け対策 491 .addBinaryBody( "upload" , 492 file , 493 ContentType.DEFAULT_BINARY , 494 file.getName() ) 495 .build(); 496 method.setEntity( entity ); 497 } 498 } 499 else { 500 // GET でのパラメータのマージ。きちんとした方法がわかるまでの暫定処置 501 final String getStr = reqParamBuf.length() == 0 502 ? urlStr 503 : reqParamBuf.toString() ; 504 505 if( isDebug ) { System.out.println( "GET URL=" + getStr ); } 506 507 method = new HttpGet( getStr ); 508 } 509 510 final HttpClientContext context = HttpClientContext.create(); 511// if( ckStore != null ) { // 8.0.0.0 (2021/07/31) 未使用 512// context.setCookieStore(ckStore); 513// } 514 515 String body = null; 516 try( CloseableHttpClient client = getClient() ; 517 CloseableHttpResponse response = client.execute(method,context) ) { 518 519 rpsCode = response.getCode(); // 8.0.0.0 (2021/07/31) 520 if( isDebug ) { System.out.println( "readData=" + rpsCode ); } 521 rpsMessage = code2Message( rpsCode ).trim(); // 8.0.0.0 (2021/07/31) 522 523 final HttpEntity entity = response.getEntity(); 524 525 if( entity == null ) { 526 body = rpsMessage; // HttpEntity が受け取れなかった場合は、メッセージを表示します。 527 } 528 else { 529 // body は一度しか処理できない。EntityUtils.toByteArray( entity ) か、EntityUtils.toString( entity, charset ); 530 531 final URI uri = method.getUri(); 532 533 // バイナリファイルとして受け取る場合。成功(200番台)のみ処理します。 534 if( !StringUtil.isNull( dwldFile ) && rpsCode >= 200 && rpsCode < 300 ) { 535 final byte[] dwnBody = EntityUtils.toByteArray( entity ); 536 final String text = new String( dwnBody,charset ); 537 538 // 一旦Form認証画面のHTMLが返ってくるので、その中から j_security_check を探してくる。 539 if( text.contains( "j_security_check" ) ) { 540 body = formLogin( client,uri ); // Form認証時の再接続処理 541 } 542 else { 543 Files.write( Paths.get( dwldFile ) , dwnBody ); 544 body = dwldFile; 545 } 546 } 547 else { 548 // form認証チェックが必要なので、バイナリでも文字列で受け取る。 549 body = EntityUtils.toString( entity, charset ); 550 // 一旦Form認証画面のHTMLが返ってくるので、その中から j_security_check を探してくる。 551 if( body.contains( "j_security_check" ) ) { 552 body = formLogin( client,uri ); // Form認証時の再接続処理 553 } 554 else if( authJson != null ) { // 8.0.0.0 (2021/08/31) 555 body = jsonLogin( client ); // 認証時の再接続処理 556 body = jsonDataget( client,uri ); // 認証後の再接続処理 557 } 558 } 559 } 560 EntityUtils.consume(entity); // リソースを解放 561 } 562 // 8.0.0.0 (2021/07/31) Add 563 catch( final ParseException | URISyntaxException ex ) { 564 throw new OgRuntimeException( ex ); 565 } 566 567 return body; 568 } 569 570 /** 571 * 接続先の HttpClient オブジェクトを作成します。 572 * 573 * 接続に必要な情報を、設定します。 574 * CloseableHttpClient は、AutoCloseable を継承しています。 575 * 576 * 7.2.5.0 (2020/06/01) 577 * 通常、HttpClientはGETの場合は自動でリダイレクト処理しますが、 578 * POSTの場合は、302が返るだけでリダイレクト処理しません。 579 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3[HTTP RFC 2616]で規定されています。 580 * ここでは、ダウンロードファイルがあり、POSTの場合だけ強制的に 581 * 582 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 583 * @og.rev 7.2.5.0 (2020/06/01) postRedirect(POST時に強制的にリダイレクト) 584 * @og.rev 8.0.0.0 (2021/07/31) httpclient4 → httpclient5 対応 585 * 586 * @return HttpConnectionオブジェクト 587 * @throws IOException 入出力エラーが発生したとき 588 */ 589 private CloseableHttpClient getClient() throws MalformedURLException { 590 final HttpClientBuilder clBuild = HttpClientBuilder.create(); 591 592 final BasicCookieStore cookieStore = new BasicCookieStore(); 593 clBuild.setDefaultCookieStore(cookieStore) ; 594 595 if( timeout >= 0 ) { 596 final RequestConfig.Builder reqConfig = RequestConfig.custom(); 597 reqConfig.setConnectTimeout( timeout ,TimeUnit.SECONDS ); // 8.0.0.0 (2021/07/31) timeoutの単位は(秒) 598 599 clBuild.setDefaultRequestConfig( reqConfig.build() ); 600 } 601 602 // 7.2.5.0 (2020/06/01) postRedirect(POST時に強制的にリダイレクト) 603 // 8.0.0.0 (2021/07/31) httpclient5-5.1対応により LaxRedirectStrategy 廃止の為一旦削除 604 // if( postRedirect ) { 605 // clBuild.setRedirectStrategy( new LaxRedirectStrategy() ); 606 // } 607 608 // headers (初期設定も入っているので、通常は、empty にはならない。) 609 if( !headers.isEmpty() ) { 610 clBuild.setDefaultHeaders( headers ); 611 } 612 613 // Proxy 614 if( proxy != null ) { 615 clBuild.setProxy( proxy ); 616 } 617 618 // Auth 619 // https://github.com/apache/httpcomponents-client/blob/5.1.x/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientAuthentication.java 620 if( !StringUtil.isNull( user ) ) { 621 final URL url = new URL( urlStr ); 622 final AuthScope scope = new AuthScope( url.getHost(), url.getPort() ); 623 final Credentials cred = new UsernamePasswordCredentials( user ,pass.toCharArray() ); // 8.0.0.0 (2021/07/31) 624 625 final BasicCredentialsProvider credProvider = new BasicCredentialsProvider(); // 8.0.0.0 (2021/07/31) 626 credProvider.setCredentials( scope,cred ); 627 clBuild.setDefaultCredentialsProvider( credProvider ); 628 } 629 630 // // (デフォルトのHttpClientは、最新のRFC準拠ヘッダーを理解するのが困難です。) 631 // // RequestConfig に、CookieSpecs.STANDARD を設定しているが、効果なければ、使わなくしてしまう。 632 // clBuild.disableCookieManagement(); 633 634 return clBuild.build(); // HttpClient httpClient = HttpClientBuilder.create().*****.build(); 635 } 636 637 /** 638 * 接続先に使用する引数(パラメータ)を追加します。 639 * 640 * これは、POSTでも、GETでも使用できます。 641 * POSTの場合は、NameValuePair として、HttpPost に、Entity としてセットするデータを設定します。 642 * GET の場合は、既存の接続先URLに、&キー=値・・・・ で、追記します。 643 * すでに、パラメータが指定済みの場合は、& で、そうでなければ、? で連結します。 644 * ここで指定するパラメータは、内部で、urlEncode しますので、そのままの文字列でかまいません。 645 * 646 * デフォルトは、GETですが、Internet Explorer では URL に最大 2,083 文字しか指定できないため、 647 * それ以上の場合は、POST に自動で切り替えます。 648 * 649 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 650 * 651 * @param key パラメータキー(nullの場合は、登録しません) 652 * @param val パラメータ値 653 */ 654 public void addRequestProperty( final String key, final String val ) { 655 if( !StringUtil.isNull( key ) ) { 656 reqParamList.add( new BasicNameValuePair( key,val ) ); // POST のときのパラメータ。(GETでも使えるはず?) 657 658 if( !isPost ) { // 明らかに、GET でない場合は、この処理を行わない。 659 if( reqParamBuf.length() == 0 ) { // 初めての場合 660 reqParamBuf.append( urlStr ) 661 .append( urlStr.indexOf( '?' ) > 0 ? '&' : '?' ) 662 .append( StringUtil.urlEncode2( key ) ) 663 .append( '=' ) 664 .append( StringUtil.urlEncode2( val ) ); // null のときは、長さゼロ文字列になる。 665 } 666 else if( reqParamBuf.length() > MAX_GET_LENGTH ) { 667 if( isDebug ) { System.out.println( "GET → POST変更: URLの長さ制限<" + reqParamBuf.length() ); } 668 isPost = true; // GETで送れるURLの長さ制限を超えた場合は、POSTにする。 669 } 670 else { 671 reqParamBuf.append( '&' ) 672 .append( StringUtil.urlEncode2( key ) ) 673 .append( '=' ) 674 .append( StringUtil.urlEncode2( val ) ); // null のときは、長さゼロ文字列になる。 675 } 676 } 677 } 678 } 679 680 /** 681 * setRequestPropertyでセットするデータを設定します。 682 * 683 * keys,vals各々、カンマ区切りで分解します。 684 * 685 * @og.rev 5.10.16.0 (2019/10/04) 追加 686 * 687 * @param keys パラメータキー(カンマ区切り) 688 * @param vals パラメータ(カンマ区切り) 689 */ 690 public void setRequestProperty( final String keys, final String vals ) { 691 if( keys != null && keys.length() > 0 && vals != null && vals.length() > 0 ){ 692 final String[] propKeys = StringUtil.csv2Array( keys ); 693 final String[] propVals = StringUtil.csv2Array( vals ); 694 695 if( propKeys.length == propVals.length && propKeys.length > 0 ) { 696 for( int i=0; i<propKeys.length; i++ ) { 697 addRequestProperty( propKeys[i], propVals[i] ); 698 } 699 } 700 else { 701 final String errMsg = "パラメータのキーと、値の数が一致しません。" + CR 702 + " key=[" + keys + "]" + CR 703 + " val=[" + vals + "]" ; 704 throw new IllegalArgumentException( errMsg ); 705 } 706 } 707 } 708 709 /** 710 * 指定のURLに対して、コネクトするのに使用するプロキシ設定を行います。 711 * このときに、ヘッダー情報を内部変数に設定しておきます。 712 * 713 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 714 * 715 * @param host 接続するプロキシのホスト名(nullの場合は、登録しません) 716 * @param port 接続するプロキシのポート番号 717 */ 718 public void setProxy( final String host,final int port ) { 719 if( !StringUtil.isNull( host ) ) { 720 proxy = new HttpHost( host , port ); 721 } 722 } 723 724 /** 725 * Header として、HttpClient にセットするデータを設定します。 726 * 727 * 例えばJSON形式でPOSTする場合は通常"Content-Type", "application/json"を指定します。 728 * 729 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 730 * 731 * @param key パラメータキー(nullの場合は、登録しません) 732 * @param val パラメータ値(nullの場合は、登録しません) 733 */ 734 public void addHeaderProperty( final String key, final String val ) { 735 if( !StringUtil.isNull( key ) && !StringUtil.isNull( val ) ) { 736 headers.add( new BasicHeader( key,val ) ); 737 } 738 } 739 740 /** 741 * URL接続先のバイナリファイルをダウンロード取得します。 742 * 743 * 取得したファイルは、dwldFile にバイナリのまま書き込まれます。 744 * よって、エンコードの指定は不要です。 745 * 746 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 747 * 748 * @param dwldFile ダウンロードするファイル名。 749 * @throws IOException 入出力エラーが発生したとき 750 */ 751 public void setDownloadFile( final String dwldFile ) throws IOException { 752 this.dwldFile = dwldFile; 753 } 754 755 /** 756 * URL接続先のバイナリファイルをアップロードします。 757 * 758 * 取得したファイルは、upldFile にバイナリのまま書き込まれます。 759 * よって、エンコードの指定は不要です。 760 * アップロード は、multipart/form-data で送信するため、isPost = true を 761 * 内部的に設定しておきます。 762 * 763 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 764 * @og.rev 7.2.5.0 (2020/06/01) upldFileのnull判定を入れます。 765 * 766 * @param upldFile アップロードするファイル名。 767 * @throws IOException 入出力エラーが発生したとき 768 */ 769 public void setUploadFile( final String upldFile ) throws IOException { 770 if( upldFile != null ) { 771 this.upldFile = upldFile; 772 isPost = true; 773 } 774 } 775 776 /** 777 * エンコード情報を設定します。 778 * 779 * 初期値は、UTF-8 です。 780 * 781 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 782 * 783 * @param chset エンコード情報(nullの場合は、初期値:UTF-8 になります) 784 */ 785 public void setCharset( final String chset ) { 786 if( !StringUtil.isNull( chset ) ) { 787 charset = chset; 788 } 789 } 790 791 /** 792 * 接続タイムアウト時間を(秒)で指定します 793 * 794 * 実際には、org.apache.http.client.config.RequestConfig に対して、 795 * .setConnectTimeout( timeout * 1000 ) 796 * .setSocketTimeout( timeout * 1000 ) 797 * のように、 1000倍して設定しています。 798 * 0 は、無限のタイムアウト、マイナスは、設定しません。(つまりJavaの初期値のまま) 799 * 800 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 801 * 802 * @param tout タイムアウト時間(秒) (ゼロは、無制限) 803 */ 804 public void setTimeout( final int tout ) { 805 timeout = tout; 806 } 807 808 /** 809 * trueの場合、POSTを使用して接続します(初期値:false)。 810 * 811 * 通常はGETですが、外部から強制的に、POSTで送信したい場合に、 812 * 設定します。 813 * ただし、バイナリファイルをアップロードか、URLの長さ制限が、 814 * {@value #MAX_GET_LENGTH} を超えた場合は、内部で自動的に、post にします。 815 * 816 * @og.rev 6.9.0.1 (2018/02/05) 新規作成 817 * 818 * @param usePost true:POST使用/false:通常(GET) 819 */ 820 public void usePost( final boolean usePost ) { 821 isPost = usePost; 822 } 823 824 /** 825 * jsonによる2フェーズ認証を行う場合の設定。 826 * 827 * 認証用のデータをJSON形式の文字列で設定します。 828 * urlは、認証するためのURLを指定します。 829 * 830 * @og.rev 8.0.0.0 (2021/08/31) 新規作成 831 * 832 * @param json 認証用のデータを設定するJSON文字列 833 * @param url JSON文字列で認証を行うURL(無ければnull) 834 */ 835 public void setAuthJson( final String json,final String url ) { 836 if( json != null && url != null ) { 837 authJson = json; 838 authURL = url; 839 } 840 // null 設定も可能とする。 841 // else { 842 // final String errMsg = "setAuthJson を使用する場合は、authJsonとauthURLの両方を設定してください。" + CR 843 // + " authJson=[" + json + "]" + CR 844 // + " authURL =[" + url + "]" ; 845 // throw new IllegalArgumentException( errMsg ); 846 // } 847 } 848 849 /** 850 * パラメータをJSONで指定する場合に使用します。 851 * 852 * JSON形式でパラメータを指定する場合に使用します。 853 * $XXXX$ 文字列は、先のjson認証で取得した各種パラメータを割り当てます。 854 * 855 * @og.rev 8.0.0.0 (2021/08/31) 新規作成 856 * 857 * @param json JSON文字列のパラメータ 858 */ 859 public void setReqJson( final String json ) { 860 if( json == null ) { return; } 861 862 reqJson = json; 863 864 // $xxxxx$ 文字列を見つけて、Mapのキーとして登録しておく 865 int st = reqJson.indexOf( '$' ); 866 while( st >= 0 ) { 867 final int ed = reqJson.indexOf( '$',st+1 ); 868 if( ed > 0 ) { 869 jsonMap.put( reqJson.substring( st+1,ed ) , "" ); // $ は含めず 870 } 871 st = reqJson.indexOf( '$',ed+1 ); 872 } 873 } 874 875 /** 876 * trueの場合、POST時に強制的にリダイレクトを行います(初期値:false)。 877 * 878 * @og.rev 7.2.5.0 (2020/06/01) postRedirect(POST時に強制的にリダイレクト) 879 * @og.rev 8.0.0.0 (2021/07/31) httpclient5-5.1対応により LaxRedirectStrategy 廃止の為一旦削除 880 * 881 * @param useRedirect true:POST時に強制的にリダイレクト/false:通常 882 */ 883 public void setPostRedirect( final boolean useRedirect ) { 884 postRedirect = useRedirect; 885 } 886 887 /** 888 * trueの場合、適度にデバッグ用のメッセージを出力します(初期値:false)。 889 * 890 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 891 * 892 * @param isDebug true:デバッグ用のメッセージを出力/false:通常 893 */ 894 public void setDebug( final boolean isDebug ) { 895 this.isDebug = isDebug; 896 } 897 898 /** 899 * 実行結果のステータスコード 情報を取得します。 900 * 901 * 結果は、#readData() メソッドをコールしないと取れません。 902 * 未実行の場合は、-1 がセットされています。 903 * 904 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 905 * 906 * @return 結果コード 情報 907 * @see #readData() 908 */ 909 public int getCode() { return rpsCode; } 910 911 /** 912 * メッセージ 情報を取得します。 913 * 914 * 結果は、#readData() メソッドをコールしないと取れません。 915 * 未実行の場合は、null がセットされています。 916 * 917 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 918 * 919 * @return メッセージ 情報 920 */ 921 public String getMessage() { return rpsMessage; } 922 923 /** 924 * HttpURLConnection のレスポンスコードに対応するメッセージ文字列を返します。 925 * 926 * HttpURLConnection の getResponseCode() メソッドにより取得された、HTTPレスポンスコード 927 * に対応する文字列を返します。この文字列は、HttpURLConnection で定義された 928 * static 定数のコメントを、定義しています。 929 * 930 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 931 * 932 * @param code HTTPレスポンスコード 933 * 934 * @return レスポンスコードに対応する文字列 935 * @og.rtnNotNull 936 * @see HttpURLConnection#HTTP_ACCEPTED 937 */ 938 public static String code2Message( final int code ) { 939 final String msg ; 940 switch( code ) { 941 case 100 : msg = "100: 要求は続行可能です。" ; break; 942 case 101 : msg = "101: プロトコルを切り替えます。" ; break; 943 case HttpURLConnection.HTTP_OK : msg = "200: OK です。" ; break; 944 case HttpURLConnection.HTTP_CREATED : msg = "201: 作成されました。" ; break; 945 case HttpURLConnection.HTTP_ACCEPTED : msg = "202: 受け入れられました。" ; break; 946 case HttpURLConnection.HTTP_NOT_AUTHORITATIVE : msg = "203: 信頼できない情報です。" ; break; 947 case HttpURLConnection.HTTP_NO_CONTENT : msg = "204: コンテンツがありません。" ; break; 948 case HttpURLConnection.HTTP_RESET : msg = "205: コンテンツをリセットします。" ; break; 949 case HttpURLConnection.HTTP_PARTIAL : msg = "206: 部分的なコンテンツです。" ; break; 950 case HttpURLConnection.HTTP_MULT_CHOICE : msg = "300: 複数の選択肢があります。" ; break; 951 case HttpURLConnection.HTTP_MOVED_PERM : msg = "301: 永続的に移動されました。" ; break; 952 case HttpURLConnection.HTTP_MOVED_TEMP : msg = "302: 一時的なリダイレクト。" ; break; 953 case HttpURLConnection.HTTP_SEE_OTHER : msg = "303: ほかを参照してください。" ; break; 954 case HttpURLConnection.HTTP_NOT_MODIFIED : msg = "304: 変更されていません。" ; break; 955 case HttpURLConnection.HTTP_USE_PROXY : msg = "305: プロキシを使用します。" ; break; 956 case 306 : msg = "306: 仕様の拡張案です。" ; break; 957 case 307 : msg = "307: 一時的なリダイレクトです。" ; break; 958 case HttpURLConnection.HTTP_BAD_REQUEST : msg = "400: 不当な要求です。" ; break; 959 case HttpURLConnection.HTTP_UNAUTHORIZED : msg = "401: 認証されませんでした。" ; break; 960 case HttpURLConnection.HTTP_PAYMENT_REQUIRED : msg = "402: 支払いが必要です。" ; break; 961 case HttpURLConnection.HTTP_FORBIDDEN : msg = "403: 禁止されています。" ; break; 962 case HttpURLConnection.HTTP_NOT_FOUND : msg = "404: 見つかりませんでした。" ; break; 963 case HttpURLConnection.HTTP_BAD_METHOD : msg = "405: メソッドは許可されません。" ; break; 964 case HttpURLConnection.HTTP_NOT_ACCEPTABLE : msg = "406: 受け入れられません。" ; break; 965 case HttpURLConnection.HTTP_PROXY_AUTH : msg = "407: プロキシの認証が必要です。" ; break; 966 case HttpURLConnection.HTTP_CLIENT_TIMEOUT : msg = "408: 要求がタイムアウトしました。" ; break; 967 case HttpURLConnection.HTTP_CONFLICT : msg = "409: 重複しています。" ; break; 968 case HttpURLConnection.HTTP_GONE : msg = "410: 存在しません。" ; break; 969 case HttpURLConnection.HTTP_LENGTH_REQUIRED : msg = "411: 長さが必要です。" ; break; 970 case HttpURLConnection.HTTP_PRECON_FAILED : msg = "412: 前提条件が満たされていません。" ; break; 971 case HttpURLConnection.HTTP_ENTITY_TOO_LARGE : msg = "413: 要求のエンティティが大きすぎます。" ; break; 972 case HttpURLConnection.HTTP_REQ_TOO_LONG : msg = "414: 要求のURIが大きすぎます。" ; break; 973 case HttpURLConnection.HTTP_UNSUPPORTED_TYPE : msg = "415: サポートされないメディアタイプです。" ; break; 974 case 416 : msg = "416: 要求された範囲は不十分です。" ; break; 975 case 417 : msg = "417: 要求どおりの処理が不可能です。" ; break; 976 case HttpURLConnection.HTTP_INTERNAL_ERROR : msg = "500: 内部サーバエラーです。" ; break; 977 case HttpURLConnection.HTTP_NOT_IMPLEMENTED : msg = "501: 実装されていません。" ; break; 978 case HttpURLConnection.HTTP_BAD_GATEWAY : msg = "502: 誤ったゲートウェイです。" ; break; 979 case HttpURLConnection.HTTP_UNAVAILABLE : msg = "503: サービスが利用できません。" ; break; 980 case HttpURLConnection.HTTP_GATEWAY_TIMEOUT : msg = "504: ゲートウェイがタイムアウトしました。" ; break; 981 case HttpURLConnection.HTTP_VERSION : msg = "505: サポートされていないHTTPバージョンです。" ; break; 982 default : msg = code + ": 未定義" ; break; 983 } 984 return msg ; 985 } 986 987 /** 988 * サンプル実行用のメインメソッド 989 * 990 * <pre> 991 * Usage: java org.opengion.fukurou.util.HttpConnect [-post=キー:ファイル名] … url [user:passwd] 992 * args[A] : url URLを指定します。GETの場合、パラメータは ?KEY=VALです 993 * args[*] : [-param=key:value] POST/GET時のパラメータのキーと値を:で区切って指定します。(複数回指定可) 994 * args[*] : [-header=key:value] ヘッダーに設定するパラメータのキーと値を:で区切って指定します。(複数回指定可) 995 * args[*] : [-auth=user:pass] BASIC認証のエリアへのアクセス時のユーザーとパスワードを指定します 996 * args[*] : [-useForm=true/false] 認証方式にFORM認証を指定する場合、trueをセットします(初期値:false) 8.0.0.0 (2021/08/20) 997 * args[*] : [-proxy=host:port] proxy を使用する場合のホストとポートを指定します。 998 * args[*] : [-timeout=3] 接続タイムアウト時間を(秒)で指定します(初期値:無指定) 999 * args[*] : [-encode=UTF-8] エンコードを指定します。(初期値は UTF-8) 1000 * args[*] : [-out=ファイル名] 結果をファイルに出力します。初期値は標準出力です 1001 * args[*] : [-download=ファイル名] ファイル名を指定して、ダウンロードします 1002 * args[*] : [-upload=ファイル名] ファイル名を指定して、multipart/form-dataでファイルアップロードします 1003 * args[*] : [-postRedirect=true] POST時に強制的にリダイレクトを行います(GET時は自動でリダイレクトします)(初期値:false) 7.2.5.0 (2020/06/01) 1004 * args[*] : [-usePost=true] POSTを強制的に使用する場合にセットします(初期値:false) 8.0.0.0 (2021/08/20) 1005 * args[*] : [-errEx=true/false] trueの場合、レスポンスコードが、4XX,5XX の時に RuntimeException を投げます(初期値:false) 1006 * args[*] : [#・・・・] コメント引数。(BATファイル上に残しておきたいが、使用したくない場合など) 1007 * args[*] : [-debug=true/false] trueの場合、適度にデバッグ用のメッセージを出力します(初期値:false) 1008 * </pre> 1009 * 1010 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 1011 * @og.rev 7.2.5.0 (2020/06/01) postRedirect(POST時に強制的にリダイレクト)引数を追加 1012 * 1013 * @param args コマンド引数配列 1014 * @throws IOException 入出力エラーが発生したとき 1015 */ 1016 public static void main( final String[] args ) throws IOException { 1017 if( args.length < 2 ) { 1018 LogWriter.log( "Usage: java org.opengion.fukurou.util.HttpConnect [-data/-binary] … url" ); 1019 LogWriter.log( " args[A] : url URLを指定します。GETの場合、パラメータは ?KEY=VALです" ); 1020 LogWriter.log( " args[*] : [-param=key:value] POST/GET時のパラメータのキーと値を:で区切って指定します。(複数回指定可)" ); 1021 LogWriter.log( " args[*] : [-header=key:value] ヘッダーに設定するパラメータのキーと値を:で区切って指定します。(複数回指定可)" ); 1022 LogWriter.log( " args[*] : [-auth=user:pass] BASIC認証/FORM認証のエリアへのアクセス時のユーザーとパスワードを指定します" ); 1023// LogWriter.log( " args[*] : [-useForm=true/false] 認証方式にFORM認証を指定する場合、trueをセットします(初期値:false)" ); 1024 LogWriter.log( " args[*] : [-proxy=host:port] proxy を使用する場合のホストとポートを指定します。" ); 1025 LogWriter.log( " args[*] : [-timeout=3] 接続タイムアウト時間を(秒)で指定します(初期値:無指定)" ); 1026 LogWriter.log( " args[*] : [-encode=UTF-8] エンコードを指定します。(初期値は UTF-8)" ); 1027 LogWriter.log( " args[*] : [-out=ファイル名] 結果をファイルに出力します。初期値は標準出力です" ); 1028 LogWriter.log( " args[*] : [-download=ファイル名] ファイル名を指定して、ダウンロードします" ); 1029 LogWriter.log( " args[*] : [-upload=ファイル名] ファイル名を指定して、multipart/form-dataでファイルアップロードします" ); 1030 LogWriter.log( " args[*] : [-postRedirect=true] POST時に強制的にリダイレクトを行います(GET時は自動でリダイレクトします)(初期値:false)" ); 1031 LogWriter.log( " args[*] : [-usePost=true] POSTを強制的に使用する場合にセットします(初期値:false)" ); 1032 LogWriter.log( " args[*] : [-errEx=true/false] trueの場合、レスポンスコードが、4XX,5XX の時に RuntimeException を投げます(初期値:false)" ); 1033 LogWriter.log( " args[*] : [-authJson=JSONコード] JSONコードで認証する場合に使用します。8.0.0.0 (2021/08/31)" ); 1034 LogWriter.log( " args[*] : [-authURL=認証用URL] JSONコードで認証するURLを指定します。8.0.0.0 (2021/08/31)" ); 1035 LogWriter.log( " args[*] : [#・・・・] コメント引数。(BATファイル上に残しておきたいが、使用したくない場合など)" ); 1036 LogWriter.log( " args[*] : [-debug=true/false] trueの場合、適度にデバッグ用のメッセージを出力します(初期値:false)" ); 1037 return; 1038 } 1039 1040 String urlStr = null ; 1041 final List<String> paramKey = new ArrayList<>(); // パラメーターキー 1042 final List<String> paramVal = new ArrayList<>(); // パラメーター値 1043 final List<String> headerKey = new ArrayList<>(); // パラメーターキー 1044 final List<String> headerVal = new ArrayList<>(); // パラメーター値 1045 1046 String userPass = null ; // -auth 1047// boolean useForm = false ; // -useForm // 8.0.0.0 (2021/08/20) 1048 String proxy = null ; // -proxy 1049 int timeout = -1 ; // -timeout 1050 String encode = DEFAULT_CHARSET ; // -encode 1051 String outFile = null ; // -out 1052 String dwldFile = null ; // -download 1053 String upldFile = null ; // -upload 1054 boolean isEx = false ; // -errEx 1055 boolean isDebug = false ; // -debug 1056 boolean postRedirect = false ; // -postRedirect // 7.2.5.0 (2020/06/01) postRedirect(POST時に強制的にリダイレクト) 1057 boolean nonWriter = false ; // -out 指定で見つからない場合 1058 boolean isPost = false ; // -usePost 1059 String authJson = null ; // -authJson // 8.0.0.0 (2021/08/31) 1060 String authURL = null ; // -authURL // 8.0.0.0 (2021/08/31) 1061 String reqJson = null ; // -reqJson // 8.0.0.0 (2021/08/31) 1062 1063// int code = -1; 1064 1065 for( final String arg : args ) { 1066 if( arg.startsWith( "-param=" ) ) { 1067 final String[] prm = StringUtil.csv2Array( arg.substring( "-param=".length() ) , '=' , 2 ); 1068 paramKey.add( prm[0] ); 1069 paramVal.add( prm[1] ); 1070 } 1071 else if( arg.startsWith( "-header=" ) ) { 1072 final String[] prm = StringUtil.csv2Array( arg.substring( "-header=".length() ) , '=' , 2 ); 1073 headerKey.add( prm[0] ); 1074 headerVal.add( prm[1] ); 1075 } 1076 else if( arg.startsWith( "-auth=" ) ) { 1077 userPass = arg.substring( "-auth=".length() ); 1078 if( StringUtil.isNull( userPass ) ) { 1079 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 1080 } 1081 } 1082// else if( arg.startsWith( "-useForm=" ) ) { 1083// useForm = "true".equalsIgnoreCase( arg.substring( "-useForm=".length() ) ); 1084// } 1085 else if( arg.startsWith( "-proxy=" ) ) { 1086 proxy = arg.substring( "-proxy=".length() ); 1087 if( StringUtil.isNull( proxy ) ) { 1088 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 1089 } 1090 } 1091 else if( arg.startsWith( "-timeout=" ) ) { 1092 timeout = Integer.parseInt( arg.substring( "-timeout=".length() ) ); 1093 } 1094 else if( arg.startsWith( "-encode=" ) ) { 1095 encode = arg.substring( "-encode=".length() ); 1096 if( StringUtil.isNull( encode ) ) { 1097 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 1098 } 1099 } 1100 else if( arg.startsWith( "-out=" ) ) { 1101 outFile = arg.substring( "-out=".length() ); 1102 if( StringUtil.isNull( outFile ) ) { 1103 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 1104 } 1105 else { 1106 if( "null".equalsIgnoreCase( outFile ) || "none".equalsIgnoreCase( outFile ) ) { 1107 outFile = null; 1108 nonWriter = true; 1109 } 1110 } 1111 } 1112 else if( arg.startsWith( "-download=" ) ) { 1113 dwldFile = arg.substring( "-download=".length() ); 1114 if( StringUtil.isNull( dwldFile ) ) { 1115 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 1116 } 1117 } 1118 else if( arg.startsWith( "-upload=" ) ) { 1119 upldFile = arg.substring( "-upload=".length() ); 1120 if( StringUtil.isNull( upldFile ) ) { 1121 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 1122 } 1123 } 1124 else if( arg.startsWith( "-errEx=" ) ) { 1125 isEx = "true".equalsIgnoreCase( arg.substring( "-errEx=".length() ) ); 1126 } 1127 // 7.2.5.0 (2020/06/01) postRedirect(POST時に強制的にリダイレクト) 1128 else if( arg.startsWith( "-postRedirect=" ) ) { 1129 postRedirect = "true".equalsIgnoreCase( arg.substring( "-postRedirect=".length() ) ); 1130 } 1131 else if( arg.startsWith( "-debug=" ) ) { 1132 isDebug = "true".equalsIgnoreCase( arg.substring( "-debug=".length() ) ); 1133 } 1134 else if( arg.startsWith( "-usePost=" ) ) { 1135 isPost = "true".equalsIgnoreCase( arg.substring( "-usePost=".length() ) ); 1136 } 1137 else if( arg.startsWith( "-authJson=" ) ) { // 8.0.0.0 (2021/08/31) 1138 authJson = arg.substring( "-authJson=".length() ); 1139 if( StringUtil.isNull( authJson ) ) { 1140 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 1141 } 1142 } 1143 else if( arg.startsWith( "-authURL=" ) ) { // 8.0.0.0 (2021/08/31) 1144 authURL = arg.substring( "-authURL=".length() ); 1145 if( StringUtil.isNull( authURL ) ) { 1146 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 1147 } 1148 } 1149 else if( arg.startsWith( "-reqJson=" ) ) { // 8.0.0.0 (2021/08/31) 1150 reqJson = arg.substring( "-reqJson=".length() ); 1151 if( StringUtil.isNull( reqJson ) ) { 1152 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 1153 } 1154 } 1155 else if( StringUtil.startsChar( arg , '-' ) ) { // 引数が未定義(処理は継続させます。) 1156 System.err.println( "Error Argment:" + arg ); 1157 } 1158 else if( StringUtil.startsChar( arg , '#' ) ) { // 引数がコメント 1159 continue; 1160 } 1161 else { 1162 urlStr = arg; 1163 } 1164 } 1165 1166 try { // try catch を入れます。 1167 final HttpConnect conn = new HttpConnect( urlStr,userPass ); 1168 conn.usePost( isPost ); 1169 conn.setDebug( isDebug ); // 最初に入れておけば、それ以降、有効になります。 1170 1171 for( int i=0; i<paramKey.size(); i++ ) { 1172 conn.addRequestProperty( paramKey.get(i) , paramVal.get(i) ); 1173 } 1174 1175 for( int i=0; i<headerKey.size(); i++ ) { 1176 conn.addHeaderProperty( headerKey.get(i) , headerVal.get(i) ); 1177 } 1178 1179 // 6.8.1.3 (2017/08/04) proxy の設定 1180 if( !StringUtil.isNull( proxy ) ) { 1181 final String[] prm = StringUtil.csv2Array( proxy , ':' , 2 ); 1182 final String host = prm[0]; 1183 final int port = Integer.parseInt( prm[1] ); 1184 conn.setProxy( host , port ); 1185 } 1186 1187 conn.setCharset( encode ); // encode 指定 1188 conn.setTimeout( timeout ); // timeout属性追加 1189 conn.setUploadFile( upldFile ); 1190 conn.setDownloadFile( dwldFile ); 1191 conn.setPostRedirect( postRedirect ); // 7.2.5.0 (2020/06/01) 1192 conn.setAuthJson( authJson,authURL ); // 8.0.0.0 (2021/08/31) 1193 conn.setReqJson( reqJson ); // 8.0.0.0 (2021/08/31) 1194 1195 final String outData = conn.readData(); // 8.0.0.0 (2021/08/20) テスト用 1196 1197 try( PrintWriter writer = StringUtil.isNull( outFile ) 1198 ? FileUtil.getLogWriter( "System.out" ) 1199 : FileUtil.getPrintWriter( new File( outFile ),encode ) ) { 1200 if( !nonWriter ) { 1201 writer.println( outData ); 1202 } 1203 final int code = conn.getCode(); 1204 1205 // isEx=trueの場合、レスポンスコードが、4XX,5XX の時に RuntimeException を投げます 1206 if( code >= 400 ) { 1207 final String errMsg = conn.getMessage(); 1208 writer.println( errMsg ); 1209 if( isEx ) { 1210 throw new OgRuntimeException( errMsg ); 1211 } 1212 else { 1213 System.exit( code ); 1214 } 1215 } 1216 } 1217 } 1218 catch( final Throwable th ) { 1219 // throw new OgRuntimeException( th ); 1220 System.err.println( th.getMessage() ); 1221 } 1222 } 1223}