2016년 12월 18일 일요일

httpclient(http)사용시 page이동(html page 요청할때 상대 주소와 절대 주소 처리)

httpclient를 사용하는 이유는 주로 webpage를 java를 이용해서 접속을 할때 사용하게 됩니다. 사용하다가 몇가지 중요한 사실을 알게되었는데요. 여기에 정리하여 봅니다.
해당내용은 httpclient에 국한 되는 내용은 아니고 html page를 직접 받아서 처리할때 알아두어야 하는 내용입니다.

1) 상대주소와 절대주소

Page를 web에서 절대 주소를 나타낼때는 '/' 를 사용하게 됩니다.
http://abc.com/aaa/index.html 라고 요청한 페이지에서 abc.com이 host 주소가 되고 /next.html 링크를 요청했다면 http://abc.com/next.html 이 요청되어질 것입니다.
http://abc.com/aaa/index.html 라고 요청한 페이지에서 ../next.html 이 요청되어지면 http://abc.com/aaa/../next.html 이게 되면서 http://abc.com/next.html 이 요청되어 집니다. 하지만 http GET 호출시 http://abc.com/aaa/../next.html 이런식으로 호출 되면 서버쪽에서 .. 처리를 해야하는데 일반적으로 처리하지 못하는 서버가 발생합니다.

정리
last url : abc.com/aaa/index.html
host : abc.com
get : /next.html => abc.com/next.html
page : abc.com/next.html

last url : abc.com/aaa/index.html
host : abc.com
get : ../next.html => abc.com/next.html
page : abc.com/next.html

2) URI normalize

따라서 http client로 page요청을 할때 ".." "." 경로를 정리해주어야 합니다.
이 과정을 normalize라고 합니다.
두가지를 구현하여 보았습니다. urlChg라는 메소드는 host와 이전 요청된 url을 인자로 넣고 atag의 href 주소를 넣으면 get해야하는 경로를 얻게 됩니다.
설명이 장황하고 길게 느껴질지 모르나, host는 절대 경로를 사용할때 사용하는 최상위 주소가 됩니다

import java.lang.String;
import java.net.URI;

// one class needs to have a main() method
public class HelloWorld
{
  // arguments are passed using the text field below this editor
  public static void main(String[] args)
  {
    System.out.println(normalize("http://abc.com/aaa/../next.html"));
    System.out.println(urlChg("http://abc.com","http://abc.com/aaa/index.html","../next.html"));
    System.out.println(urlChg("http://abc.com","http://abc.com/aaa/index.html",".././abc/../next.html"));
    System.out.println(urlChg("http://abc.com","http://abc.com/aaa/index.html","next.html"));
    System.out.println(urlChg("http://abc.com","http://abc.com/aaa/index.html","/next.html"));
    System.out.println(urlChg("http://abc.com","http://abc.com/aaa/","/next.html"));
    System.out.println(urlChg("http://abc.com","http://abc.com/aaa/","next.html"));
  }
  public static String urlChg(String host, String url, String add)
  {
    if(add.startsWith("/")){
      return host+add;
    }else{
      if(url.endsWith("/")){
        return url+add;
      }
    }
    String str = url.substring(0,url.lastIndexOf('/'))+"/"+add;
    URI uri = URI.create(str);
    uri=uri.normalize();
    return uri.toString();
  }
  public static String normalize(String str)
  {
    URI uri = URI.create(str);
    uri=uri.normalize();
    return uri.toString();
  }
}
------------------------------- result http://abc.com/next.html http://abc.com/next.html http://abc.com/next.html http://abc.com/aaa/next.html http://abc.com/next.html http://abc.com/next.html http://abc.com/aaa/next.html

위 내용에 문제가 있어서 추가로 구현하였습니다.
add되는 주소가 새로운 scheme로 시작되는 경우 즉 http,https등으로 site가 변경되는 경우
위 메소드에서는 제대로 처리하지 못하였습니다.
또한 인자가 2개가 있어서 host를 미리 저장하고 있어야 하는 문제도 해결하였습니다.
package test;

import java.net.URI;
import java.util.List;

public class Test {
 public static void main(String[] args) {
  System.out.println(calcNextUrl("http://www.a.b.c/","abc/def/ghi"));
  System.out.println(calcNextUrl("http://www.a.b.c/abc","def/ghi"));
  System.out.println(calcNextUrl("http://www.a.b.c/abc","/def/ghi"));
  System.out.println(calcNextUrl("http://www.a.b.c/abc","../def/ghi"));
  System.out.println(calcNextUrl("http://www.a.b.c/abc","http://d.e.f/def/ghi"));
 }
 public static String calcNextUrl(String thisurl, String add)
 {
  System.out.println("This:["+thisurl + "] + Add:["+add+"]");
  URI thisuri = URI.create(thisurl);
  String data = thisuri.getScheme() + "://" + thisuri.getHost();
  if(thisuri.getPort()!=-1) data=":"+thisuri.getPort();
  if(add.startsWith("/")) data=data+add;
  else if(add.startsWith("http")) data=add;
  else {
   data=thisurl;
   if(data.endsWith("/")) data=data+add;
   else data=data+"/"+add;
  }

  URI returi = URI.create(data);
  returi = returi.normalize();
  if( !returi.toString().startsWith("http") ){
   System.out.println("Error");
  }
  return returi.toString();
 }
}

결과
This:[http://www.a.b.c/] + Add:[abc/def/ghi]
http://www.a.b.c/abc/def/ghi
This:[http://www.a.b.c/abc] + Add:[def/ghi]
http://www.a.b.c/abc/def/ghi
This:[http://www.a.b.c/abc] + Add:[/def/ghi]
http://www.a.b.c/def/ghi
This:[http://www.a.b.c/abc] + Add:[../def/ghi]
http://www.a.b.c/def/ghi
This:[http://www.a.b.c/abc] + Add:[http://d.e.f/def/ghi]
http://d.e.f/def/ghi


3) HTTP redirection

HTTP response의 302,301 응답은 redirection이며 page를 자동으로 다음 페이지를 이동해서 요청을 해야합니다.
하지만 httpclient를 사용하면 자동으로 다음 페이지가 로딩됩니다. 단 GET 요청일때만 그렇습니다. POST 로 page를 요청했다면 직접 구현해야합니다.
그래서 다음 페이지가 로딩될때 자동으로 요청되어지면 page의 경로가 변경되게 되면 앞에서 설명한 상대 주소의 다음 link를 get할때 어려움이 있습니다. 따라서 execute가 되고나면 host와 get한 페이지 정보를 얻어오는 함수를 이용하여 마지막에 요청된 page가 어디인지 저장해 두어야 합니다.

댓글 없음:

댓글 쓰기