2010-03-10 2 views
2

JSON을 반환하는 Alfresco Webscripts를 호출하고 있습니다. 나는 GET 요청을 사용하여 완벽하게 작동한다. 그러나 파일 POST를 수행하면 Alfresco 서버가 파일을 올바르게 수신하고 JSON 응답을 되돌려 보내지만 이번에는 응답을 통해 Javascript가 콜백을 처리하는 대신 브라우저가 다운로드를 요구합니다.HttpUrlConnection Post 브라우저가 JSON을 Java 프록시에서 다운로드하게합니다.

이제는 이러한 모든 호출이 HttpUrlConnection을 사용하는 "집에서 만든"역방향 프록시 (아래 참조)를 통과합니다. 이 프록시는 모든 호출을 다른 호스트에서 실행중인 Alfresco로 라우트합니다. 다른 모든 것은 잘 작동합니다 (PNG, 텍스트, HTML, GET 요청, 심지어 인증). GET 및 POST 응답에서 Content-Type은 "application/json; charset = UTF-8"입니다.

모든 응답을 주셔서 감사합니다.

import java.io.*; 
import java.net.HttpURLConnection; 
import java.net.URL; 
import java.util.*; 
import javax.servlet.*; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
import org.apache.commons.codec.binary.Base64; 

public class ReverseProxy extends GenericServlet{ 

public static final String SERVER_URL = "serverURL"; 
protected String serverURL; 
protected boolean debug; 

public ReverseProxy(){ 
} 

public void init(ServletConfig config) throws ServletException { 
    super.init(config); 
    debug = Boolean.valueOf(config.getInitParameter("debug")).booleanValue(); 
    serverURL = config.getInitParameter("serverURL"); 
    if(serverURL == null){ 
     throw new ServletException("ReverseProxy servlet initialization parameter 'serverURL' not defined"); 
    } 
} 

public void service(ServletRequest req, ServletResponse resp) throws ServletException, IOException { 
    InputStream inputStream; 
    OutputStream outputStream; 
    Exception exception; 
    if(debug){System.out.println("ReverseProxy.service()");} 
    HttpServletRequest request; 
    HttpServletResponse response; 
    try{ 
     request = (HttpServletRequest)req; 
     response = (HttpServletResponse)resp; 
    } 
    catch(ClassCastException e){ 
     throw new ServletException("non-HTTP request or response"); 
    } 
    String method = request.getMethod(); 
    StringBuffer urlBuffer = new StringBuffer(); 
    urlBuffer.append(serverURL); 
    urlBuffer.append(request.getServletPath()); 
    if(request.getPathInfo() != null) 
     urlBuffer.append(request.getPathInfo()); 
    if(request.getQueryString() != null){ 
     urlBuffer.append('?'); 
     urlBuffer.append(request.getQueryString()); 
    } 
    URL url = new URL(urlBuffer.toString()); 

    //pass authentication 
    String user=null, password=null; 

    Set entrySet = req.getParameterMap().entrySet(); 
    Map headers = new HashMap(); 
    for (Object anEntrySet : entrySet) { 
     Map.Entry header = (Map.Entry) anEntrySet; 
     String key = (String) header.getKey(); 
     String value = ((String[]) header.getValue())[0]; 
     if ("user".equals(key)) { 
      user = value; 
     } else if ("password".equals(key)) { 
      password = value; 
     }else { 
      headers.put(key, value); 
     } 
    } 

    String userpass = null; 
    if (user != null && userpass!=null) { 
     userpass = user+":"+password; 
    } 
    String auth = request.getHeader("Authorization"); 
    if(auth != null){ 
     if (auth.toUpperCase().startsWith("BASIC ")){ 
      String userpassEncoded = auth.substring(6); 
      userpass = new String(Base64.decodeBase64(userpassEncoded.getBytes())); 
     } 
    } 

    String digest=null; 
    if (userpass!=null) { 
     if(debug){System.out.println("ReverseProxy found userpass:" + userpass);} 
     digest = "Basic " + new String(Base64.encodeBase64((userpass).getBytes())); 
    } 
    else{ 
     if(debug){System.out.println("ReverseProxy found no auth credentials");} 
    } 

    //do connection 
    HttpURLConnection connection = null; 
    connection = (HttpURLConnection) url.openConnection(); 
    if (digest != null) {connection.setRequestProperty("Authorization", digest);} 

    connection.setRequestMethod(method); 
    connection.setDoInput(true); 

    if(method.equals("POST")){ 
     if(request.getHeader("Content-Type") != null){ 
      if(debug){System.out.println("ReverseProxy Content-Type: " + request.getHeader("Content-Type"));} 
      if(debug){System.out.println("ReverseProxy Content-Length: " + request.getHeader("Content-Length"));} 
      if(request.getHeader("Content-Type").indexOf("multipart/form-data") != -1){ 
       connection.setRequestProperty("Content-Type", request.getHeader("Content-Type")); 
       connection.setRequestProperty("Content-Length", request.getHeader("Content-Length")); 
      } 
     } 
     connection.setDoOutput(true); 
    } 
    if(debug){ 
     System.out.println((new StringBuilder()).append("ReverseProxy: URL=").append(url).append(" method=").append(method).toString()); 
    } 

    //set headers 
    Set headersSet = headers.entrySet(); 
    for (Object aHeadersSet : headersSet) { 
     Map.Entry header = (Map.Entry) aHeadersSet; 
     connection.setRequestProperty((String) header.getKey(), (String) header.getValue()); 
    } 

    connection.connect(); 
    inputStream = null; 
    outputStream = null; 
    try{ 
     if(method.equals("POST")){ 
      javax.servlet.ServletInputStream servletInputStream = request.getInputStream(); 
      outputStream = connection.getOutputStream(); 
      copy(servletInputStream, outputStream); 
     } 
     response.setContentLength(connection.getContentLength()); 
     response.setContentType(connection.getContentType()); 
     if(debug){System.out.println("ReverseProxy Connection Content-Type: " + connection.getContentType());} 
     response.setCharacterEncoding(connection.getContentEncoding()); 
     String cacheControl = connection.getHeaderField("Cache-Control"); 
     if(cacheControl != null){ 
      response.setHeader("Cache-Control", cacheControl); 
     } 
     int responseCode = connection.getResponseCode(); 
     response.setStatus(responseCode); 

     if(responseCode == 401){ 
      response.setHeader("WWW-Authenticate", "Basic realm=\"Login Required\""); 
     } 

     for(Iterator i = connection.getHeaderFields().entrySet().iterator() ; i.hasNext() ;){ 
      Map.Entry mapEntry = (Map.Entry)i.next(); 
      if(mapEntry.getKey()!=null){ 
       response.setHeader(mapEntry.getKey().toString(), ((List)mapEntry.getValue()).get(0).toString()); 
      } 
     } 

     //if(debug){System.out.println("ReverseProxy Connection Content-Disposition: " + connection.getHeaderField("Content-Disposition"));} 

     if(debug){System.out.println((new StringBuilder()).append("ReverseProxy: response code '").append(responseCode).append("' from ").append(url).toString());} 
     if (responseCode == 200 || responseCode == 201) { 
      inputStream = connection.getInputStream(); 
     } 
     else{ 
      inputStream = connection.getErrorStream(); 
     } 

     javax.servlet.ServletOutputStream servletOutputStream = response.getOutputStream(); 
     copy(inputStream, servletOutputStream); 
    } 
    catch(IOException ex){ 
     if(debug) 
      ex.printStackTrace(); 
     throw ex; 
    } 
    finally{ 
     //if(inputStream == null) goto _L0; else goto _L0 
     //break; 
    } 
    if(inputStream != null){ 
     inputStream.close(); 
    } 
    if(outputStream != null){ 
     outputStream.close(); 
    } 
    inputStream.close(); 
    if(outputStream != null){ 
     outputStream.close(); 
    } 
    //throw exception; 
} 

public long copy(InputStream input, OutputStream output) throws IOException{ 
    byte buffer[] = new byte[4096]; 
    long count = 0L; 
    for(int n = 0; -1 != (n = input.read(buffer));){ 
     output.write(buffer, 0, n); 
     count += n; 
    } 

    output.flush(); 
    if(debug) 
     System.err.println((new StringBuilder()).append("copy ").append(count).append(" bytes").toString()); 
    return count; 
} 

}

답변

2

나는 문제가 클라이언트 측 또는 옆에있는 오해에 더 많은 것 같다. 브라우저 자체에서 처리 방법을 알 수 없기 때문에 콘텐츠 형식이 application/json 일 때 브라우저가 파일을 다운로드하라는 메시지를 표시하면 은 올바른 동작입니다. 브라우저는 적어도 text/* 또는 image/*의 콘텐츠 유형과 일치하는 모든 것을 표시 할 수 있습니다.

일반적으로 JSON 응답은 JavaScript에 의해 내부적으로 처리되며 콘텐츠 유형이 application/json 인 완쾌 반응을 완벽하게 처리 할 수 ​​있습니다. text/plain 또는 text/javascript으로 변경하여 테스트 할 수 있습니다 (text/*과 일치하므로 브라우저에 표시됨). 하지만 JSON의 경우 올바른 콘텐츠 유형은 실제로 application/json입니다.

+0

알아두기. 요청이 Javascript에서 전송 된 XMLHTTPREQUEST 인 경우 "application/json"콘텐츠 유형이 인식되고 다운로드가 발생하지 않습니다. 이는 GET 및 POST 요청 모두에 해당됩니다. 파일 업로드를 수행하는 경우 JQuery, ExtJS 등의 라이브러리는 "application/x-www-form-urlencoded"설정으로 숨겨진 양식을 만들고 게시합니다 (사용자 상호 작용없이 모두 게시). 이는 응답이 자바 스크립트가 아니라 브라우저에 의해 해석되고 있음을 의미합니다. 이 문제를 해결하는 유일한 방법은 콘텐츠 유형을 "text/html"로 설정하는 것입니다 ("text/plain"이 아닐 경우 또는 브라우저가 태그를 추가하려고 시도하는 경우). – BigBadOwl

2

요청이 자바 스크립트에서 보낸 XMLHttpRequest의 다음 "응용 프로그램/JSON"이 경우 내 댓글)

에 따라 (해결)이며, JSON을 열/다운로드 올바른 도구를 사용할 때 그냥 유지 콘텐츠 유형이 이해되고 다운로드가 발생하지 않습니다. 이는 GET 및 POST 요청 모두에 해당됩니다. 파일 업로드를 수행하는 경우 JQuery, ExtJS 등의 라이브러리는 "application/x-www-form-urlencoded"설정으로 숨겨진 양식을 만들고 게시합니다 (사용자 상호 작용없이 모두 게시). 이는 응답이 자바 스크립트가 아니라 브라우저에 의해 해석되고 있음을 의미합니다. 이 문제를 해결하는 유일한 방법은 반환하는 JSON의 콘텐츠 유형을 "text/html"("text/plain"이 아닌 브라우저)로 설정하는 것입니다. 그렇지 않으면 브라우저가 태그를 추가하려고 시도합니다.

+0

"..."application/x-www-form-urlencoded "로 숨겨진 양식을 만들고 게시하십시오 ..." Ajax 호출을 직접 작성하여 "application/json" . 하지만 적어도 json이나 x-www-form-urlencoded 이건 상관없이 작동합니다. 그래도 내 자신의 아약스 코딩 양식을 만들었지. – Zlatko

관련 문제