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