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; 078import 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 */ 349 private String jsonLogin( final CloseableHttpClient client ) { 350 String body = null; 351 352 try { 353 final ClassicHttpRequest login = new HttpPost( authURL ); 354 355 // 8.0.0.0 (2021/08/31) 356 login.setHeader("Content-type", "application/json"); 357 final HttpEntity stringEntity = new StringEntity(authJson,ContentType.APPLICATION_JSON); 358 login.setEntity( stringEntity ); 359 360 try( CloseableHttpResponse response = client.execute(login) ) { 361 final HttpEntity entity = response.getEntity(); 362 363 rpsCode = response.getCode(); // 8.0.0.0 (2021/07/31) 364 rpsMessage = code2Message( rpsCode ).trim(); // 8.0.0.0 (2021/07/31) 365 if( isDebug ) { System.out.println( "jsonLogin=" + rpsCode ); } 366 367 body = EntityUtils.toString( entity, charset ); 368 369 if( isDebug ) { System.out.println( "Login=" + body ); } 370 371 // ログイン時のリターンJSONから、パラメータを取得するMapを作成します。 372 if( !jsonMap.isEmpty() ) { 373 for( final String key : jsonMap.keySet() ) { 374 final int st = body.indexOf( key ); 375 if( st >= 0 ) { 376 int ed = body.indexOf( ',',st+key.length() ); 377 final StringBuilder buf = new StringBuilder(); 378 if( ed > 0 ) { 379 for( int i=st+key.length(); i<ed; i++ ) { 380 final char ch = body.charAt(i); 381 if( ch != '"' && ch != ':' && ch != ' ' ) { 382 buf.append( ch ); 383 } 384 } 385 } 386 jsonMap.put( key,buf.toString() ); 387 if( isDebug ) { System.out.println( "Map=" + key + ":" + buf.toString() ); } 388 } 389 } 390 } 391 392 EntityUtils.consume(entity); // リソースを解放 393 } 394 } 395 catch( final IOException | ParseException ex ) { 396 throw new OgRuntimeException( ex ); 397 } 398 399 return body ; 400 } 401 402 /** 403 * 特別版ログイン 404 * 405 * @og.rev 8.0.0.0 (2021/08/31) httpclient4 → httpclient5 対応 406 */ 407 private String jsonDataget( final CloseableHttpClient client , final URI uri ) { 408 String body = null; 409 410 try { 411 final ClassicHttpRequest httpReq ; 412 413 if( reqJson == null ) { 414 httpReq = new HttpGet( uri ); // public/html/reportMain.html の時 415 } 416 else { 417 httpReq = new HttpPost( uri ); 418 httpReq.setHeader("Content-type", "application/json"); 419 420 String tempJson = reqJson; 421 if( !jsonMap.isEmpty() ) { 422 for( final Map.Entry<String,String> entry : jsonMap.entrySet() ) { 423 tempJson = tempJson.replace( '$'+entry.getKey()+'$' , entry.getValue() ); 424 } 425 } 426 427 if( isDebug ) { System.out.println( "reqJson=" + tempJson ); } 428 429 final HttpEntity stringEntity = new StringEntity(tempJson,ContentType.APPLICATION_JSON); 430 httpReq.setEntity( stringEntity ); 431 } 432 433 try( CloseableHttpResponse response = client.execute(httpReq) ) { 434 final HttpEntity entity = response.getEntity(); 435 436 rpsCode = response.getCode(); // 8.0.0.0 (2021/07/31) 437 rpsMessage = code2Message( rpsCode ).trim(); // 8.0.0.0 (2021/07/31) 438 if( isDebug ) { System.out.println( "jsonDataget=" + rpsCode ); } 439 440 body = EntityUtils.toString( entity, charset ); 441 EntityUtils.consume(entity); // リソースを解放 442 } 443 } 444 catch( final IOException | ParseException ex ) { 445 throw new OgRuntimeException( ex ); 446 } 447 448 return body ; 449 } 450 451 /** 452 * URL接続先のデータを取得します。 453 * 454 * この処理の前に、必要な情報を設定して置いてください。 455 * また、code や message は、このメソッドを実行しないと取得できませんのでご注意ください。 456 * 457 * 取得したデータは、指定のURL へのアクセスのみです。 458 * 通常のWebブラウザは、イメージや、JavaScriptファイル、CSSファイルなど、 459 * 各種ファイル毎にHTTP接続を行い、取得して、レンダリングします。 460 * このメソッドでの処理では、それらのファイル内に指定されているURLの 461 * 再帰的な取得は行いません。 462 * よって、フレーム処理なども行いません。 463 * 464 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 465 * @og.rev 8.0.0.0 (2021/07/31) httpclient4 → httpclient5 対応 466 * 467 * @return 接続結果 468 * @og.rtnNotNull 469 * @throws IOException 入出力エラーが発生したとき 470 * @throws MalformedURLException URLの形式が間違っている場合 471 */ 472 public String readData() throws IOException , MalformedURLException { 473 final ClassicHttpRequest method ; // 8.0.0.0 (2021/07/31) 474 if( isPost ) { 475 if( isDebug ) { System.out.println( "POST URL=" + urlStr ); } 476 method = new HttpPost( urlStr ); 477 478 if( !reqParamList.isEmpty() ) { 479 method.setEntity( new UrlEncodedFormEntity( reqParamList ) ); // 8.0.0.0 (2021/07/31) 480 if( isDebug ) { reqParamList.forEach( v -> System.out.println( "PARAM KEY=" + v.getName() + " , VAL=" + v.getValue() ) ); } 481 } 482 483 if( !StringUtil.isNull( upldFile ) ) { 484 final File file = new File( upldFile ); 485 if( isDebug ) { System.out.println( " MULTI FILE=" + file ); } 486 final HttpEntity entity = MultipartEntityBuilder.create() 487 .setCharset( StandardCharsets.UTF_8 ) // ファイル名の文字化け対策 488 .addBinaryBody( "upload" , 489 file , 490 ContentType.DEFAULT_BINARY , 491 file.getName() ) 492 .build(); 493 method.setEntity( entity ); 494 } 495 } 496 else { 497 // GET でのパラメータのマージ。きちんとした方法がわかるまでの暫定処置 498 final String getStr = reqParamBuf.length() == 0 499 ? urlStr 500 : reqParamBuf.toString() ; 501 502 if( isDebug ) { System.out.println( "GET URL=" + getStr ); } 503 504 method = new HttpGet( getStr ); 505 } 506 507 final HttpClientContext context = HttpClientContext.create(); 508// if( ckStore != null ) { // 8.0.0.0 (2021/07/31) 未使用 509// context.setCookieStore(ckStore); 510// } 511 512 String body = null; 513 try( CloseableHttpClient client = getClient() ; 514 CloseableHttpResponse response = client.execute(method,context) ) { 515 516 rpsCode = response.getCode(); // 8.0.0.0 (2021/07/31) 517 if( isDebug ) { System.out.println( "readData=" + rpsCode ); } 518 rpsMessage = code2Message( rpsCode ).trim(); // 8.0.0.0 (2021/07/31) 519 520 final HttpEntity entity = response.getEntity(); 521 522 if( entity == null ) { 523 body = rpsMessage; // HttpEntity が受け取れなかった場合は、メッセージを表示します。 524 } 525 else { 526 // body は一度しか処理できない。EntityUtils.toByteArray( entity ) か、EntityUtils.toString( entity, charset ); 527 528 final URI uri = method.getUri(); 529 530 // バイナリファイルとして受け取る場合。成功(200番台)のみ処理します。 531 if( !StringUtil.isNull( dwldFile ) && rpsCode >= 200 && rpsCode < 300 ) { 532 final byte[] dwnBody = EntityUtils.toByteArray( entity ); 533 final String text = new String( dwnBody,charset ); 534 535 // 一旦Form認証画面のHTMLが返ってくるので、その中から j_security_check を探してくる。 536 if( text.contains( "j_security_check" ) ) { 537 body = formLogin( client,uri ); // Form認証時の再接続処理 538 } 539 else { 540 Files.write( Paths.get( dwldFile ) , dwnBody ); 541 body = dwldFile; 542 } 543 } 544 else { 545 // form認証チェックが必要なので、バイナリでも文字列で受け取る。 546 body = EntityUtils.toString( entity, charset ); 547 // 一旦Form認証画面のHTMLが返ってくるので、その中から j_security_check を探してくる。 548 if( body.contains( "j_security_check" ) ) { 549 body = formLogin( client,uri ); // Form認証時の再接続処理 550 } 551 else if( authJson != null ) { // 8.0.0.0 (2021/08/31) 552 body = jsonLogin( client ); // 認証時の再接続処理 553 body = jsonDataget( client,uri ); // 認証後の再接続処理 554 } 555 } 556 } 557 EntityUtils.consume(entity); // リソースを解放 558 } 559 // 8.0.0.0 (2021/07/31) Add 560 catch( final ParseException | URISyntaxException ex ) { 561 throw new OgRuntimeException( ex ); 562 } 563 564 return body; 565 } 566 567 /** 568 * 接続先の HttpClient オブジェクトを作成します。 569 * 570 * 接続に必要な情報を、設定します。 571 * CloseableHttpClient は、AutoCloseable を継承しています。 572 * 573 * 7.2.5.0 (2020/06/01) 574 * 通常、HttpClientはGETの場合は自動でリダイレクト処理しますが、 575 * POSTの場合は、302が返るだけでリダイレクト処理しません。 576 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3[HTTP RFC 2616]で規定されています。 577 * ここでは、ダウンロードファイルがあり、POSTの場合だけ強制的に 578 * 579 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 580 * @og.rev 7.2.5.0 (2020/06/01) postRedirect(POST時に強制的にリダイレクト) 581 * @og.rev 8.0.0.0 (2021/07/31) httpclient4 → httpclient5 対応 582 * 583 * @return HttpConnectionオブジェクト 584 * @throws IOException 入出力エラーが発生したとき 585 */ 586 private CloseableHttpClient getClient() throws MalformedURLException { 587 final HttpClientBuilder clBuild = HttpClientBuilder.create(); 588 589 final BasicCookieStore cookieStore = new BasicCookieStore(); 590 clBuild.setDefaultCookieStore(cookieStore) ; 591 592 if( timeout >= 0 ) { 593 final RequestConfig.Builder reqConfig = RequestConfig.custom(); 594 reqConfig.setConnectTimeout( timeout ,TimeUnit.SECONDS ); // 8.0.0.0 (2021/07/31) timeoutの単位は(秒) 595 596 clBuild.setDefaultRequestConfig( reqConfig.build() ); 597 } 598 599 // 7.2.5.0 (2020/06/01) postRedirect(POST時に強制的にリダイレクト) 600 // 8.0.0.0 (2021/07/31) httpclient5-5.1対応により LaxRedirectStrategy 廃止の為一旦削除 601 // if( postRedirect ) { 602 // clBuild.setRedirectStrategy( new LaxRedirectStrategy() ); 603 // } 604 605 // headers (初期設定も入っているので、通常は、empty にはならない。) 606 if( !headers.isEmpty() ) { 607 clBuild.setDefaultHeaders( headers ); 608 } 609 610 // Proxy 611 if( proxy != null ) { 612 clBuild.setProxy( proxy ); 613 } 614 615 // Auth 616 // https://github.com/apache/httpcomponents-client/blob/5.1.x/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientAuthentication.java 617 if( !StringUtil.isNull( user ) ) { 618 final URL url = new URL( urlStr ); 619 final AuthScope scope = new AuthScope( url.getHost(), url.getPort() ); 620 final Credentials cred = new UsernamePasswordCredentials( user ,pass.toCharArray() ); // 8.0.0.0 (2021/07/31) 621 622 final BasicCredentialsProvider credProvider = new BasicCredentialsProvider(); // 8.0.0.0 (2021/07/31) 623 credProvider.setCredentials( scope,cred ); 624 clBuild.setDefaultCredentialsProvider( credProvider ); 625 } 626 627 // // (デフォルトのHttpClientは、最新のRFC準拠ヘッダーを理解するのが困難です。) 628 // // RequestConfig に、CookieSpecs.STANDARD を設定しているが、効果なければ、使わなくしてしまう。 629 // clBuild.disableCookieManagement(); 630 631 return clBuild.build(); // HttpClient httpClient = HttpClientBuilder.create().*****.build(); 632 } 633 634 /** 635 * 接続先に使用する引数(パラメータ)を追加します。 636 * 637 * これは、POSTでも、GETでも使用できます。 638 * POSTの場合は、NameValuePair として、HttpPost に、Entity としてセットするデータを設定します。 639 * GET の場合は、既存の接続先URLに、&キー=値・・・・ で、追記します。 640 * すでに、パラメータが指定済みの場合は、& で、そうでなければ、? で連結します。 641 * ここで指定するパラメータは、内部で、urlEncode しますので、そのままの文字列でかまいません。 642 * 643 * デフォルトは、GETですが、Internet Explorer では URL に最大 2,083 文字しか指定できないため、 644 * それ以上の場合は、POST に自動で切り替えます。 645 * 646 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 647 * 648 * @param key パラメータキー(nullの場合は、登録しません) 649 * @param val パラメータ値 650 */ 651 public void addRequestProperty( final String key, final String val ) { 652 if( !StringUtil.isNull( key ) ) { 653 reqParamList.add( new BasicNameValuePair( key,val ) ); // POST のときのパラメータ。(GETでも使えるはず?) 654 655 if( !isPost ) { // 明らかに、GET でない場合は、この処理を行わない。 656 if( reqParamBuf.length() == 0 ) { // 初めての場合 657 reqParamBuf.append( urlStr ) 658 .append( urlStr.indexOf( '?' ) > 0 ? '&' : '?' ) 659 .append( StringUtil.urlEncode2( key ) ) 660 .append( '=' ) 661 .append( StringUtil.urlEncode2( val ) ); // null のときは、長さゼロ文字列になる。 662 } 663 else if( reqParamBuf.length() > MAX_GET_LENGTH ) { 664 if( isDebug ) { System.out.println( "GET → POST変更: URLの長さ制限<" + reqParamBuf.length() ); } 665 isPost = true; // GETで送れるURLの長さ制限を超えた場合は、POSTにする。 666 } 667 else { 668 reqParamBuf.append( '&' ) 669 .append( StringUtil.urlEncode2( key ) ) 670 .append( '=' ) 671 .append( StringUtil.urlEncode2( val ) ); // null のときは、長さゼロ文字列になる。 672 } 673 } 674 } 675 } 676 677 /** 678 * setRequestPropertyでセットするデータを設定します。 679 * 680 * keys,vals各々、カンマ区切りで分解します。 681 * 682 * @og.rev 5.10.16.0 (2019/10/04) 追加 683 * 684 * @param keys パラメータキー(カンマ区切り) 685 * @param vals パラメータ(カンマ区切り) 686 */ 687 public void setRequestProperty( final String keys, final String vals ) { 688 if( keys != null && keys.length() > 0 && vals != null && vals.length() > 0 ){ 689 final String[] propKeys = StringUtil.csv2Array( keys ); 690 final String[] propVals = StringUtil.csv2Array( vals ); 691 692 if( propKeys.length == propVals.length && propKeys.length > 0 ) { 693 for( int i=0; i<propKeys.length; i++ ) { 694 addRequestProperty( propKeys[i], propVals[i] ); 695 } 696 } 697 else { 698 final String errMsg = "パラメータのキーと、値の数が一致しません。" + CR 699 + " key=[" + keys + "]" + CR 700 + " val=[" + vals + "]" ; 701 throw new IllegalArgumentException( errMsg ); 702 } 703 } 704 } 705 706 /** 707 * 指定のURLに対して、コネクトするのに使用するプロキシ設定を行います。 708 * このときに、ヘッダー情報を内部変数に設定しておきます。 709 * 710 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 711 * 712 * @param host 接続するプロキシのホスト名(nullの場合は、登録しません) 713 * @param port 接続するプロキシのポート番号 714 */ 715 public void setProxy( final String host,final int port ) { 716 if( !StringUtil.isNull( host ) ) { 717 proxy = new HttpHost( host , port ); 718 } 719 } 720 721 /** 722 * Header として、HttpClient にセットするデータを設定します。 723 * 724 * 例えばJSON形式でPOSTする場合は通常"Content-Type", "application/json"を指定します。 725 * 726 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 727 * 728 * @param key パラメータキー(nullの場合は、登録しません) 729 * @param val パラメータ値(nullの場合は、登録しません) 730 */ 731 public void addHeaderProperty( final String key, final String val ) { 732 if( !StringUtil.isNull( key ) && !StringUtil.isNull( val ) ) { 733 headers.add( new BasicHeader( key,val ) ); 734 } 735 } 736 737 /** 738 * URL接続先のバイナリファイルをダウンロード取得します。 739 * 740 * 取得したファイルは、dwldFile にバイナリのまま書き込まれます。 741 * よって、エンコードの指定は不要です。 742 * 743 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 744 * 745 * @param dwldFile ダウンロードするファイル名。 746 * @throws IOException 入出力エラーが発生したとき 747 */ 748 public void setDownloadFile( final String dwldFile ) throws IOException { 749 this.dwldFile = dwldFile; 750 } 751 752 /** 753 * URL接続先のバイナリファイルをアップロードします。 754 * 755 * 取得したファイルは、upldFile にバイナリのまま書き込まれます。 756 * よって、エンコードの指定は不要です。 757 * アップロード は、multipart/form-data で送信するため、isPost = true を 758 * 内部的に設定しておきます。 759 * 760 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 761 * @og.rev 7.2.5.0 (2020/06/01) upldFileのnull判定を入れます。 762 * 763 * @param upldFile アップロードするファイル名。 764 * @throws IOException 入出力エラーが発生したとき 765 */ 766 public void setUploadFile( final String upldFile ) throws IOException { 767 if( upldFile != null ) { 768 this.upldFile = upldFile; 769 isPost = true; 770 } 771 } 772 773 /** 774 * エンコード情報を設定します。 775 * 776 * 初期値は、UTF-8 です。 777 * 778 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 779 * 780 * @param chset エンコード情報(nullの場合は、初期値:UTF-8 になります) 781 */ 782 public void setCharset( final String chset ) { 783 if( !StringUtil.isNull( chset ) ) { 784 charset = chset; 785 } 786 } 787 788 /** 789 * 接続タイムアウト時間を(秒)で指定します 790 * 791 * 実際には、org.apache.http.client.config.RequestConfig に対して、 792 * .setConnectTimeout( timeout * 1000 ) 793 * .setSocketTimeout( timeout * 1000 ) 794 * のように、 1000倍して設定しています。 795 * 0 は、無限のタイムアウト、マイナスは、設定しません。(つまりJavaの初期値のまま) 796 * 797 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 798 * 799 * @param tout タイムアウト時間(秒) (ゼロは、無制限) 800 */ 801 public void setTimeout( final int tout ) { 802 timeout = tout; 803 } 804 805 /** 806 * trueの場合、POSTを使用して接続します(初期値:false)。 807 * 808 * 通常はGETですが、外部から強制的に、POSTで送信したい場合に、 809 * 設定します。 810 * ただし、バイナリファイルをアップロードか、URLの長さ制限が、 811 * {@value #MAX_GET_LENGTH} を超えた場合は、内部で自動的に、post にします。 812 * 813 * @og.rev 6.9.0.1 (2018/02/05) 新規作成 814 * 815 * @param usePost true:POST使用/false:通常(GET) 816 */ 817 public void usePost( final boolean usePost ) { 818 isPost = usePost; 819 } 820 821 /** 822 * jsonによる2フェーズ認証を行う場合の設定。 823 * 824 * 認証用のデータをJSON形式の文字列で設定します。 825 * urlは、認証するためのURLを指定します。 826 * 827 * @og.rev 8.0.0.0 (2021/08/31) 新規作成 828 * 829 * @param json 認証用のデータを設定するJSON文字列 830 * @param url JSON文字列で認証を行うURL(無ければnull) 831 */ 832 public void setAuthJson( final String json,final String url ) { 833 if( json != null && url != null ) { 834 authJson = json; 835 authURL = url; 836 } 837 // null 設定も可能とする。 838 // else { 839 // final String errMsg = "setAuthJson を使用する場合は、authJsonとauthURLの両方を設定してください。" + CR 840 // + " authJson=[" + json + "]" + CR 841 // + " authURL =[" + url + "]" ; 842 // throw new IllegalArgumentException( errMsg ); 843 // } 844 } 845 846 /** 847 * パラメータをJSONで指定する場合に使用します。 848 * 849 * JSON形式でパラメータを指定する場合に使用します。 850 * $XXXX$ 文字列は、先のjson認証で取得した各種パラメータを割り当てます。 851 * 852 * @og.rev 8.0.0.0 (2021/08/31) 新規作成 853 * 854 * @param json JSON文字列のパラメータ 855 */ 856 public void setReqJson( final String json ) { 857 if( json == null ) { return; } 858 859 reqJson = json; 860 861 // $xxxxx$ 文字列を見つけて、Mapのキーとして登録しておく 862 int st = reqJson.indexOf( '$' ); 863 while( st >= 0 ) { 864 final int ed = reqJson.indexOf( '$',st+1 ); 865 if( ed > 0 ) { 866 jsonMap.put( reqJson.substring( st+1,ed ) , "" ); // $ は含めず 867 } 868 st = reqJson.indexOf( '$',ed+1 ); 869 } 870 } 871 872 /** 873 * trueの場合、POST時に強制的にリダイレクトを行います(初期値:false)。 874 * 875 * @og.rev 7.2.5.0 (2020/06/01) postRedirect(POST時に強制的にリダイレクト) 876 * @og.rev 8.0.0.0 (2021/07/31) httpclient5-5.1対応により LaxRedirectStrategy 廃止の為一旦削除 877 * 878 * @param useRedirect true:POST時に強制的にリダイレクト/false:通常 879 */ 880 public void setPostRedirect( final boolean useRedirect ) { 881 postRedirect = useRedirect; 882 } 883 884 /** 885 * trueの場合、適度にデバッグ用のメッセージを出力します(初期値:false)。 886 * 887 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 888 * 889 * @param isDebug true:デバッグ用のメッセージを出力/false:通常 890 */ 891 public void setDebug( final boolean isDebug ) { 892 this.isDebug = isDebug; 893 } 894 895 /** 896 * 実行結果のステータスコード 情報を取得します。 897 * 898 * 結果は、#readData() メソッドをコールしないと取れません。 899 * 未実行の場合は、-1 がセットされています。 900 * 901 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 902 * 903 * @return 結果コード 情報 904 * @see #readData() 905 */ 906 public int getCode() { return rpsCode; } 907 908 /** 909 * メッセージ 情報を取得します。 910 * 911 * 結果は、#readData() メソッドをコールしないと取れません。 912 * 未実行の場合は、null がセットされています。 913 * 914 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 915 * 916 * @return メッセージ 情報 917 */ 918 public String getMessage() { return rpsMessage; } 919 920 /** 921 * HttpURLConnection のレスポンスコードに対応するメッセージ文字列を返します。 922 * 923 * HttpURLConnection の getResponseCode() メソッドにより取得された、HTTPレスポンスコード 924 * に対応する文字列を返します。この文字列は、HttpURLConnection で定義された 925 * static 定数のコメントを、定義しています。 926 * 927 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 928 * 929 * @param code HTTPレスポンスコード 930 * 931 * @return レスポンスコードに対応する文字列 932 * @og.rtnNotNull 933 * @see HttpURLConnection#HTTP_ACCEPTED 934 */ 935 public static String code2Message( final int code ) { 936 final String msg ; 937 switch( code ) { 938 case 100 : msg = "100: 要求は続行可能です。" ; break; 939 case 101 : msg = "101: プロトコルを切り替えます。" ; break; 940 case HttpURLConnection.HTTP_OK : msg = "200: OK です。" ; break; 941 case HttpURLConnection.HTTP_CREATED : msg = "201: 作成されました。" ; break; 942 case HttpURLConnection.HTTP_ACCEPTED : msg = "202: 受け入れられました。" ; break; 943 case HttpURLConnection.HTTP_NOT_AUTHORITATIVE : msg = "203: 信頼できない情報です。" ; break; 944 case HttpURLConnection.HTTP_NO_CONTENT : msg = "204: コンテンツがありません。" ; break; 945 case HttpURLConnection.HTTP_RESET : msg = "205: コンテンツをリセットします。" ; break; 946 case HttpURLConnection.HTTP_PARTIAL : msg = "206: 部分的なコンテンツです。" ; break; 947 case HttpURLConnection.HTTP_MULT_CHOICE : msg = "300: 複数の選択肢があります。" ; break; 948 case HttpURLConnection.HTTP_MOVED_PERM : msg = "301: 永続的に移動されました。" ; break; 949 case HttpURLConnection.HTTP_MOVED_TEMP : msg = "302: 一時的なリダイレクト。" ; break; 950 case HttpURLConnection.HTTP_SEE_OTHER : msg = "303: ほかを参照してください。" ; break; 951 case HttpURLConnection.HTTP_NOT_MODIFIED : msg = "304: 変更されていません。" ; break; 952 case HttpURLConnection.HTTP_USE_PROXY : msg = "305: プロキシを使用します。" ; break; 953 case 306 : msg = "306: 仕様の拡張案です。" ; break; 954 case 307 : msg = "307: 一時的なリダイレクトです。" ; break; 955 case HttpURLConnection.HTTP_BAD_REQUEST : msg = "400: 不当な要求です。" ; break; 956 case HttpURLConnection.HTTP_UNAUTHORIZED : msg = "401: 認証されませんでした。" ; break; 957 case HttpURLConnection.HTTP_PAYMENT_REQUIRED : msg = "402: 支払いが必要です。" ; break; 958 case HttpURLConnection.HTTP_FORBIDDEN : msg = "403: 禁止されています。" ; break; 959 case HttpURLConnection.HTTP_NOT_FOUND : msg = "404: 見つかりませんでした。" ; break; 960 case HttpURLConnection.HTTP_BAD_METHOD : msg = "405: メソッドは許可されません。" ; break; 961 case HttpURLConnection.HTTP_NOT_ACCEPTABLE : msg = "406: 受け入れられません。" ; break; 962 case HttpURLConnection.HTTP_PROXY_AUTH : msg = "407: プロキシの認証が必要です。" ; break; 963 case HttpURLConnection.HTTP_CLIENT_TIMEOUT : msg = "408: 要求がタイムアウトしました。" ; break; 964 case HttpURLConnection.HTTP_CONFLICT : msg = "409: 重複しています。" ; break; 965 case HttpURLConnection.HTTP_GONE : msg = "410: 存在しません。" ; break; 966 case HttpURLConnection.HTTP_LENGTH_REQUIRED : msg = "411: 長さが必要です。" ; break; 967 case HttpURLConnection.HTTP_PRECON_FAILED : msg = "412: 前提条件が満たされていません。" ; break; 968 case HttpURLConnection.HTTP_ENTITY_TOO_LARGE : msg = "413: 要求のエンティティが大きすぎます。" ; break; 969 case HttpURLConnection.HTTP_REQ_TOO_LONG : msg = "414: 要求のURIが大きすぎます。" ; break; 970 case HttpURLConnection.HTTP_UNSUPPORTED_TYPE : msg = "415: サポートされないメディアタイプです。" ; break; 971 case 416 : msg = "416: 要求された範囲は不十分です。" ; break; 972 case 417 : msg = "417: 要求どおりの処理が不可能です。" ; break; 973 case HttpURLConnection.HTTP_INTERNAL_ERROR : msg = "500: 内部サーバエラーです。" ; break; 974 case HttpURLConnection.HTTP_NOT_IMPLEMENTED : msg = "501: 実装されていません。" ; break; 975 case HttpURLConnection.HTTP_BAD_GATEWAY : msg = "502: 誤ったゲートウェイです。" ; break; 976 case HttpURLConnection.HTTP_UNAVAILABLE : msg = "503: サービスが利用できません。" ; break; 977 case HttpURLConnection.HTTP_GATEWAY_TIMEOUT : msg = "504: ゲートウェイがタイムアウトしました。" ; break; 978 case HttpURLConnection.HTTP_VERSION : msg = "505: サポートされていないHTTPバージョンです。" ; break; 979 default : msg = code + ": 未定義" ; break; 980 } 981 return msg ; 982 } 983 984 /** 985 * サンプル実行用のメインメソッド 986 * 987 * <pre> 988 * Usage: java org.opengion.fukurou.util.HttpConnect [-post=キー:ファイル名] … url [user:passwd] 989 * args[A] : url URLを指定します。GETの場合、パラメータは ?KEY=VALです 990 * args[*] : [-param=key:value] POST/GET時のパラメータのキーと値を:で区切って指定します。(複数回指定可) 991 * args[*] : [-header=key:value] ヘッダーに設定するパラメータのキーと値を:で区切って指定します。(複数回指定可) 992 * args[*] : [-auth=user:pass] BASIC認証のエリアへのアクセス時のユーザーとパスワードを指定します 993 * args[*] : [-useForm=true/false] 認証方式にFORM認証を指定する場合、trueをセットします(初期値:false) 8.0.0.0 (2021/08/20) 994 * args[*] : [-proxy=host:port] proxy を使用する場合のホストとポートを指定します。 995 * args[*] : [-timeout=3] 接続タイムアウト時間を(秒)で指定します(初期値:無指定) 996 * args[*] : [-encode=UTF-8] エンコードを指定します。(初期値は UTF-8) 997 * args[*] : [-out=ファイル名] 結果をファイルに出力します。初期値は標準出力です 998 * args[*] : [-download=ファイル名] ファイル名を指定して、ダウンロードします 999 * args[*] : [-upload=ファイル名] ファイル名を指定して、multipart/form-dataでファイルアップロードします 1000 * args[*] : [-postRedirect=true] POST時に強制的にリダイレクトを行います(GET時は自動でリダイレクトします)(初期値:false) 7.2.5.0 (2020/06/01) 1001 * args[*] : [-usePost=true] POSTを強制的に使用する場合にセットします(初期値:false) 8.0.0.0 (2021/08/20) 1002 * args[*] : [-errEx=true/false] trueの場合、レスポンスコードが、4XX,5XX の時に RuntimeException を投げます(初期値:false) 1003 * args[*] : [#・・・・] コメント引数。(BATファイル上に残しておきたいが、使用したくない場合など) 1004 * args[*] : [-debug=true/false] trueの場合、適度にデバッグ用のメッセージを出力します(初期値:false) 1005 * </pre> 1006 * 1007 * @og.rev 6.9.0.0 (2018/01/31) 新規作成 1008 * @og.rev 7.2.5.0 (2020/06/01) postRedirect(POST時に強制的にリダイレクト)引数を追加 1009 * 1010 * @param args コマンド引数配列 1011 * @throws IOException 入出力エラーが発生したとき 1012 */ 1013 public static void main( final String[] args ) throws IOException { 1014 if( args.length < 2 ) { 1015 LogWriter.log( "Usage: java org.opengion.fukurou.util.HttpConnect [-data/-binary] … url" ); 1016 LogWriter.log( " args[A] : url URLを指定します。GETの場合、パラメータは ?KEY=VALです" ); 1017 LogWriter.log( " args[*] : [-param=key:value] POST/GET時のパラメータのキーと値を:で区切って指定します。(複数回指定可)" ); 1018 LogWriter.log( " args[*] : [-header=key:value] ヘッダーに設定するパラメータのキーと値を:で区切って指定します。(複数回指定可)" ); 1019 LogWriter.log( " args[*] : [-auth=user:pass] BASIC認証/FORM認証のエリアへのアクセス時のユーザーとパスワードを指定します" ); 1020// LogWriter.log( " args[*] : [-useForm=true/false] 認証方式にFORM認証を指定する場合、trueをセットします(初期値:false)" ); 1021 LogWriter.log( " args[*] : [-proxy=host:port] proxy を使用する場合のホストとポートを指定します。" ); 1022 LogWriter.log( " args[*] : [-timeout=3] 接続タイムアウト時間を(秒)で指定します(初期値:無指定)" ); 1023 LogWriter.log( " args[*] : [-encode=UTF-8] エンコードを指定します。(初期値は UTF-8)" ); 1024 LogWriter.log( " args[*] : [-out=ファイル名] 結果をファイルに出力します。初期値は標準出力です" ); 1025 LogWriter.log( " args[*] : [-download=ファイル名] ファイル名を指定して、ダウンロードします" ); 1026 LogWriter.log( " args[*] : [-upload=ファイル名] ファイル名を指定して、multipart/form-dataでファイルアップロードします" ); 1027 LogWriter.log( " args[*] : [-postRedirect=true] POST時に強制的にリダイレクトを行います(GET時は自動でリダイレクトします)(初期値:false)" ); 1028 LogWriter.log( " args[*] : [-usePost=true] POSTを強制的に使用する場合にセットします(初期値:false)" ); 1029 LogWriter.log( " args[*] : [-errEx=true/false] trueの場合、レスポンスコードが、4XX,5XX の時に RuntimeException を投げます(初期値:false)" ); 1030 LogWriter.log( " args[*] : [-authJson=JSONコード] JSONコードで認証する場合に使用します。8.0.0.0 (2021/08/31)" ); 1031 LogWriter.log( " args[*] : [-authURL=認証用URL] JSONコードで認証するURLを指定します。8.0.0.0 (2021/08/31)" ); 1032 LogWriter.log( " args[*] : [#・・・・] コメント引数。(BATファイル上に残しておきたいが、使用したくない場合など)" ); 1033 LogWriter.log( " args[*] : [-debug=true/false] trueの場合、適度にデバッグ用のメッセージを出力します(初期値:false)" ); 1034 return; 1035 } 1036 1037 String urlStr = null ; 1038 final List<String> paramKey = new ArrayList<>(); // パラメーターキー 1039 final List<String> paramVal = new ArrayList<>(); // パラメーター値 1040 final List<String> headerKey = new ArrayList<>(); // パラメーターキー 1041 final List<String> headerVal = new ArrayList<>(); // パラメーター値 1042 1043 String userPass = null ; // -auth 1044// boolean useForm = false ; // -useForm // 8.0.0.0 (2021/08/20) 1045 String proxy = null ; // -proxy 1046 int timeout = -1 ; // -timeout 1047 String encode = DEFAULT_CHARSET ; // -encode 1048 String outFile = null ; // -out 1049 String dwldFile = null ; // -download 1050 String upldFile = null ; // -upload 1051 boolean isEx = false ; // -errEx 1052 boolean isDebug = false ; // -debug 1053 boolean postRedirect = false ; // -postRedirect // 7.2.5.0 (2020/06/01) postRedirect(POST時に強制的にリダイレクト) 1054 boolean nonWriter = false ; // -out 指定で見つからない場合 1055 boolean isPost = false ; // -usePost 1056 String authJson = null ; // -authJson // 8.0.0.0 (2021/08/31) 1057 String authURL = null ; // -authURL // 8.0.0.0 (2021/08/31) 1058 String reqJson = null ; // -reqJson // 8.0.0.0 (2021/08/31) 1059 1060// int code = -1; 1061 1062 for( final String arg : args ) { 1063 if( arg.startsWith( "-param=" ) ) { 1064 final String[] prm = StringUtil.csv2Array( arg.substring( "-param=".length() ) , '=' , 2 ); 1065 paramKey.add( prm[0] ); 1066 paramVal.add( prm[1] ); 1067 } 1068 else if( arg.startsWith( "-header=" ) ) { 1069 final String[] prm = StringUtil.csv2Array( arg.substring( "-header=".length() ) , '=' , 2 ); 1070 headerKey.add( prm[0] ); 1071 headerVal.add( prm[1] ); 1072 } 1073 else if( arg.startsWith( "-auth=" ) ) { 1074 userPass = arg.substring( "-auth=".length() ); 1075 if( StringUtil.isNull( userPass ) ) { 1076 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 1077 } 1078 } 1079// else if( arg.startsWith( "-useForm=" ) ) { 1080// useForm = "true".equalsIgnoreCase( arg.substring( "-useForm=".length() ) ); 1081// } 1082 else if( arg.startsWith( "-proxy=" ) ) { 1083 proxy = arg.substring( "-proxy=".length() ); 1084 if( StringUtil.isNull( proxy ) ) { 1085 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 1086 } 1087 } 1088 else if( arg.startsWith( "-timeout=" ) ) { 1089 timeout = Integer.parseInt( arg.substring( "-timeout=".length() ) ); 1090 } 1091 else if( arg.startsWith( "-encode=" ) ) { 1092 encode = arg.substring( "-encode=".length() ); 1093 if( StringUtil.isNull( encode ) ) { 1094 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 1095 } 1096 } 1097 else if( arg.startsWith( "-out=" ) ) { 1098 outFile = arg.substring( "-out=".length() ); 1099 if( StringUtil.isNull( outFile ) ) { 1100 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 1101 } 1102 else { 1103 if( "null".equalsIgnoreCase( outFile ) || "none".equalsIgnoreCase( outFile ) ) { 1104 outFile = null; 1105 nonWriter = true; 1106 } 1107 } 1108 } 1109 else if( arg.startsWith( "-download=" ) ) { 1110 dwldFile = arg.substring( "-download=".length() ); 1111 if( StringUtil.isNull( dwldFile ) ) { 1112 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 1113 } 1114 } 1115 else if( arg.startsWith( "-upload=" ) ) { 1116 upldFile = arg.substring( "-upload=".length() ); 1117 if( StringUtil.isNull( upldFile ) ) { 1118 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 1119 } 1120 } 1121 else if( arg.startsWith( "-errEx=" ) ) { 1122 isEx = "true".equalsIgnoreCase( arg.substring( "-errEx=".length() ) ); 1123 } 1124 // 7.2.5.0 (2020/06/01) postRedirect(POST時に強制的にリダイレクト) 1125 else if( arg.startsWith( "-postRedirect=" ) ) { 1126 postRedirect = "true".equalsIgnoreCase( arg.substring( "-postRedirect=".length() ) ); 1127 } 1128 else if( arg.startsWith( "-debug=" ) ) { 1129 isDebug = "true".equalsIgnoreCase( arg.substring( "-debug=".length() ) ); 1130 } 1131 else if( arg.startsWith( "-usePost=" ) ) { 1132 isPost = "true".equalsIgnoreCase( arg.substring( "-usePost=".length() ) ); 1133 } 1134 else if( arg.startsWith( "-authJson=" ) ) { // 8.0.0.0 (2021/08/31) 1135 authJson = arg.substring( "-authJson=".length() ); 1136 if( StringUtil.isNull( authJson ) ) { 1137 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 1138 } 1139 } 1140 else if( arg.startsWith( "-authURL=" ) ) { // 8.0.0.0 (2021/08/31) 1141 authURL = arg.substring( "-authURL=".length() ); 1142 if( StringUtil.isNull( authURL ) ) { 1143 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 1144 } 1145 } 1146 else if( arg.startsWith( "-reqJson=" ) ) { // 8.0.0.0 (2021/08/31) 1147 reqJson = arg.substring( "-reqJson=".length() ); 1148 if( StringUtil.isNull( reqJson ) ) { 1149 System.err.println( arg + "指定した場合は、引数を設定してください。" ); 1150 } 1151 } 1152 else if( StringUtil.startsChar( arg , '-' ) ) { // 引数が未定義(処理は継続させます。) 1153 System.err.println( "Error Argment:" + arg ); 1154 } 1155 else if( StringUtil.startsChar( arg , '#' ) ) { // 引数がコメント 1156 continue; 1157 } 1158 else { 1159 urlStr = arg; 1160 } 1161 } 1162 1163 try { // try catch を入れます。 1164 final HttpConnect conn = new HttpConnect( urlStr,userPass ); 1165 conn.usePost( isPost ); 1166 conn.setDebug( isDebug ); // 最初に入れておけば、それ以降、有効になります。 1167 1168 for( int i=0; i<paramKey.size(); i++ ) { 1169 conn.addRequestProperty( paramKey.get(i) , paramVal.get(i) ); 1170 } 1171 1172 for( int i=0; i<headerKey.size(); i++ ) { 1173 conn.addHeaderProperty( headerKey.get(i) , headerVal.get(i) ); 1174 } 1175 1176 // 6.8.1.3 (2017/08/04) proxy の設定 1177 if( !StringUtil.isNull( proxy ) ) { 1178 final String[] prm = StringUtil.csv2Array( proxy , ':' , 2 ); 1179 final String host = prm[0]; 1180 final int port = Integer.parseInt( prm[1] ); 1181 conn.setProxy( host , port ); 1182 } 1183 1184 conn.setCharset( encode ); // encode 指定 1185 conn.setTimeout( timeout ); // timeout属性追加 1186 conn.setUploadFile( upldFile ); 1187 conn.setDownloadFile( dwldFile ); 1188 conn.setPostRedirect( postRedirect ); // 7.2.5.0 (2020/06/01) 1189 conn.setAuthJson( authJson,authURL ); // 8.0.0.0 (2021/08/31) 1190 conn.setReqJson( reqJson ); // 8.0.0.0 (2021/08/31) 1191 1192 final String outData = conn.readData(); // 8.0.0.0 (2021/08/20) テスト用 1193 1194 try( PrintWriter writer = StringUtil.isNull( outFile ) 1195 ? FileUtil.getLogWriter( "System.out" ) 1196 : FileUtil.getPrintWriter( new File( outFile ),encode ) ) { 1197 if( !nonWriter ) { 1198 writer.println( outData ); 1199 } 1200 final int code = conn.getCode(); 1201 1202 // isEx=trueの場合、レスポンスコードが、4XX,5XX の時に RuntimeException を投げます 1203 if( code >= 400 ) { 1204 final String errMsg = conn.getMessage(); 1205 writer.println( errMsg ); 1206 if( isEx ) { 1207 throw new OgRuntimeException( errMsg ); 1208 } 1209 else { 1210 System.exit( code ); 1211 } 1212 } 1213 } 1214 } 1215 catch( final Throwable th ) { 1216 // throw new OgRuntimeException( th ); 1217 System.err.println( th.getMessage() ); 1218 } 1219 } 1220}