跨域問題解決方案(HttpClient安全跨域 & jsonp跨域)
1 錯誤場景
今天要把專案部署到外網的時候,出現了這樣的問題, 我把兩個專案放到自己本機的tomcat下, 進行程式碼除錯, 執行
都沒有問題的, 一旦把我需要呼叫介面的專案B放到其他的伺服器上, 就會報錯, 無法通過Ajax呼叫springMVC的介面,
這是什麼原因呢?
當我使用json ajax post請求傳遞資料的時候在web端出錯:
2 初識jsonp
經過在網上查詢, 網上大多數說是跨域問題. 解決跨域問題據說是jsonp, 百度了一篇文章, 不管三七二十一就一下
子把ajax傳遞的資料型別dataType 改成為jsonp, 並使用get方式, 單純的認為, json和jsonp沒啥區別, 執行, 報錯, 如
下圖所示:
沒有了上述的 is not allowed ....的錯誤, 變成了只剩下500的錯誤, 說明jsonp起了些作用, 我的bug的問題就是在於網上說的"跨域" 。而究竟什麼是跨域呢?
3 什麼是跨域?什麼是不跨域?
上沒有過多的去測試,一句話:同一個ip、同一個網路協議、同一個埠,三者都滿足就是同一個域,否則就是
跨域問題了。而為什麼開發者最初不直接定為一切可跨域的呢?預設的為什麼都是不可跨域呢?這就涉及到了同源策
略,為了系統的安全,由Netscape提出一個著名的安全策略。現在所有支援JavaScript的瀏覽器都會使用這個策略。
所謂同源是,域名,協議,埠相同。當我們在瀏覽器中開啟百度和谷歌兩個網站時,百度瀏覽器在執行一個指令碼的
時候會檢查這個指令碼屬於哪個頁面的,即檢查是否同源,只有和百度同源的指令碼才會被執行,如果沒有同源策略,那
隨便的向百度中注入一個js指令碼,彈個惡意廣告,通過js竊取資訊,這就很不安全了。
4 跨域問題如何解決?jsonp為什麼能解決跨域問題?和json有什麼區別?
關於解決跨域問題,有多種解決方案,解決方案如下。
4.1 方案一
ajax請求地址改為自己系統的後臺地址,之後在自己的後臺用HttpClient請求url。封裝好的跨域請求url工具類
程式碼如下所示。
當然要匯入httpclient-4.3.1.jar包到自己的專案中哦。這樣把請求的引數內容放到map中,通過HttpClent來實現跨域請求。</pre><pre class="html" name="code"><span style="font-size:18px;">@SuppressWarnings("all") public final class UrlUtil { private static HttpClient httpClient = new HttpClient(); /** * @Title: getDataFromURL * @Description: 根據URL跨域獲取輸出結果,支援http * @param strURL * 要訪問的URL地址 * @param param * 引數 * @return 結果字串 * @throws Exception */ public static String getDataFromURL(String strURL, Map<String, String> param) throws Exception { URL url = new URL(strURL); URLConnection conn = url.openConnection(); conn.setDoOutput(true); OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream()); final StringBuilder sb = new StringBuilder(param.size() << 4); // 4次方 final Set<String> keys = param.keySet(); for (final String key : keys) { final String value = param.get(key); sb.append(key); // 不能包含特殊字元 sb.append('='); sb.append(value); sb.append('&'); } // 將最後的 '&' 去掉 sb.deleteCharAt(sb.length() - 1); writer.write(sb.toString()); writer.flush(); writer.close(); InputStreamReader reder = new InputStreamReader(conn.getInputStream(), "utf-8"); BufferedReader breader = new BufferedReader(reder); // BufferedWriter w = new BufferedWriter(new FileWriter("d:/1.txt")); String content = null; String result = null; while ((content = breader.readLine()) != null) { result += content; } return result; } /** * @Title: postMethod * @Description: 根據URL跨域獲取輸出結果,支援https * @param url * 要訪問的URL地址(http://www.xxx.com?) * @param urlParm * 引數(id=1212&pwd=2332) * @return 結果字串 */ public static String postMethod(String url, String urlParm) { if (null == url || "".equals(url)) { // url = "http://www.baidu.com"; return null; } PostMethod post = new PostMethod(url); // new UTF8PostMethod(url); if (null != urlParm && !"".equals(urlParm)) { String[] arr = urlParm.split("&"); NameValuePair[] data = new NameValuePair[arr.length]; for (int i = 0; i < arr.length; i++) { String name = arr[i].substring(0, arr[i].lastIndexOf("=")); String value = arr[i].substring(arr[i].lastIndexOf("=") + 1); data[i] = new NameValuePair(name, value); } post.setRequestBody(data); } int statusCode = 0; String pageContent = ""; try { statusCode = httpClient.executeMethod(post); if (statusCode == HttpStatus.SC_OK || statusCode == HttpStatus.SC_MOVED_TEMPORARILY) { pageContent = post.getResponseBodyAsString(); return pageContent; } } catch (Exception e) { e.printStackTrace(); return null; } finally { post.releaseConnection(); } return null; } public static String doPost(String url, String json) throws Exception { PostMethod postMethod = new PostMethod(url); StringRequestEntity requestEntity = new StringRequestEntity(json, "application/json", "UTF-8"); postMethod.setRequestEntity(requestEntity); /* 傳送請求,並獲取響應物件 */ int statusCode = httpClient.executeMethod(postMethod); String result = null; if (statusCode == HttpStatus.SC_OK) { result = postMethod.getResponseBodyAsString(); } else { System.out.println("Method failed: " + postMethod.getStatusLine()); } return result; } public static String post(String url, Map<String, String> params) { DefaultHttpClient httpclient = new DefaultHttpClient(); String body = null; HttpPost post = postForm(url, params); body = invoke(httpclient, post); httpclient.getConnectionManager().shutdown(); return body; } private static HttpPost postForm(String url, Map<String, String> params) { HttpPost httpost = new HttpPost(url); List<BasicNameValuePair> nvps = new ArrayList<BasicNameValuePair>(); Set<String> keySet = params.keySet(); for (String key : keySet) { BasicNameValuePair basicNameValuePair = new BasicNameValuePair(key, params.get(key)); nvps.add(basicNameValuePair); } try { httpost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8)); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return httpost; } private static String invoke(DefaultHttpClient httpclient, HttpUriRequest httpost) { HttpResponse response = sendRequest(httpclient, httpost); String body = paseResponse(response); return body; } private static HttpResponse sendRequest(DefaultHttpClient httpclient, HttpUriRequest httpost) { HttpResponse response = null; try { response = httpclient.execute(httpost); } catch (Exception e) { e.printStackTrace(); } return response; } private static String paseResponse(HttpResponse response) { HttpEntity entity = response.getEntity(); String body = null; try { body = EntityUtils.toString(entity); } catch (Exception e) { e.printStackTrace(); } return body; } public static void main(String[] args) throws Exception { String url = "http://ip:8082/security/auth/outside.do"; Map<String, String> map = new HashMap<String, String>(); map.put("loginName", "root"); map.put("code", "vms2.0"); String msg = post(url, map); JSONArray jary = JsonUtil.Json2JSONArray(msg); for (int i = 0; i < jary.length(); i++) { JSONObject obj = jary.getJSONObject(i); System.out.println(obj); // System.out.print(obj.getString("classid")); // System.out.print("\t"+obj.getString("classname")); // System.out.println("\t"+obj.getString("sonclass")); } // System.out.println(jary); } }</span>
4.2 解決方案二
兩個系統之間的資料傳遞是通過ajax post請求,傳遞json的方式來完成,我們在這裡可以使用jsonp的方式,但
是json和jsonp截然不同。首先說說神馬是json,再說神馬是jsonp。
json
全拼(javaScript Object Notation)輕量級的資料交換格式,易於機器解析和生成。基於javaScript
Programming Language,StandardECMA Edition December1999的一個子集。json完全獨立於語言的文字格
式,但是也使用類似於C語言家族的習慣(include c c++ c# java javaScript perl python)等,這些特性使得json
成為理想的資料交換語言。格式為key,value格式,具體就不贅述了。
jsonp
jsonp全拼是(json with Padding)是json的一種使用模式,padding意思為填料,墊料,填充,填補。json可
以說是名詞,而jsonp是動賓短語,兩者有聯絡,但是有本質的區別,就像米飯和把米飯填充到碗裡一樣,那米飯和
米飯填是一樣的麼,我們自然明瞭了。
jsonp算是鑽空子實現的跨域,到底通過jsonp具體如何解決跨域問題呢?本篇過長了,我們下篇分曉。goodnight...