当我使用js的ajax代码去访问另外一台机器上部署的项目的接口时,会出现交叉资源访问错误,其实就是我们通常所说的跨域访问问题。

解决方法是:在web.xml里面拦截url访问请求,然后由servlet来处理请求,将传递过来的url进行处理后变成真实的url,由java来处理这个url后返回真实的结果。

废话不多说,下面是详细的实现方法。

第一步:

web.xml

<!-- 跨域访问运营接口  -->  
    <servlet>
    <description></description>
    <display-name>PtlRequestServlet</display-name>
    <servlet-name>PtlRequestServlet</servlet-name>
    <servlet-class>com.skyform.portal.PtlRequestServlet</servlet-class>
    <init-param>
      <description>base url of portal api request</description>
      <param-name>portal.url</param-name>
      <param-value>http://172.31.100.18:8082/portal</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>PtlRequestServlet</servlet-name>
    <url-pattern>/portal</url-pattern>
  </servlet-mapping>



第二部:

在公共方法里common.js里写出ajax请求方法和url拦截方法

function getPortalBaseUrl() {
	var pathName=window.location.pathname;
    PTL_API="/"+pathName.split("/")[1]+"/portal?command=";
    return PTL_API;
};

上面的getPortalBaseUrl()方法是我调用的地址的前缀部分

下面是ajax普通的get和post请求方法

function queryDataGet(url, callback) {
	$.ajax({
		type : 'GET',
		'url' : url,
		dataType : 'json',
		contentType : "application/json; charset=utf-8",
		"success" : function(data) {
			callback(data);
		},
		error : function(error) {
			console.log(error);
		}
	});
};
//监控中列表项选用“POST”方法获取数据
function queryDataPost(url,requestParam,callback) {
    $.ajax({
        type: 'POST',
        'url': url,
        dataType : 'json',
        data:requestParam,
        contentType : "application/json; charset=utf-8",
        "success" : function(data){
            callback(data);
        },
        error : function(error) {
            console.log(error);
        }
    });
};



下面是带头信息的ajax的get和post方法

function queryTokenGet(url, token, resourcePool, callback) {
	$.ajax({
		type : 'GET',
		'url' : url,
		async: false,
		beforeSend :function(xhr){
			   xhr.setRequestHeader('token',token);
			   xhr.setRequestHeader('resourcePool',resourcePool);
			 },
		dataType : 'json',
		contentType : "application/json; charset=utf-8",
		"success" : function(data) {
			callback(data);
		},
		error : function(error) {
			console.log(error);
		}
	});
};
//选用“POST”方法获取数据
function queryTokenPost(url,token,resourcePool,requestParam,callback) {
    $.ajax({
        type: 'POST',
        'url': url,
        async: false,
        beforeSend :function(xhr){
			   xhr.setRequestHeader('token',token);
			   xhr.setRequestHeader('resourcePool',resourcePool);
			 },
        dataType : 'json',
        data:requestParam,
        contentType : "application/json; charset=utf-8",
        "success" : function(data){
            callback(data);
        },
        error : function(error) {
            console.log(error);
        }
    });
};

上面只写了方法,下面是调用的具体代码

var cmd = "/rest/aggregation/getListVirtualMachines";
var prams = {
	id : virtualmachineid
};
queryDataPost(getPrUrl() + cmd, JSON.stringify(prams), function(result) {
	//将返回的result数据信息进行展示
});

第二步:com.skyform.portal.PtlRequestServlet接到请求后处理请求

package com.company.portal;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class PtlRequestServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	private String ptlUrl;

	public PtlRequestServlet() {
	}

	public void init(ServletConfig config) throws ServletException {
		ptlUrl = config.getInitParameter("portal.url");
		if (ptlUrl == null)
			ptlUrl = "http://localhost:8082/portal";
	}

	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		System.out.println("PtlRequestServlet.java--------GET");
		String result = PtlRedirector.getResponseGet(request, ptlUrl);
		response.setCharacterEncoding("UTF-8");
		PrintWriter writer = response.getWriter();
		writer.write(result);
		writer.close();
	}

	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		// request.setCharacterEncoding("UTF-8");
		System.out.println("PtlRequestServlet.java--------POST");
		String result = PtlRedirector.getResponsePost(request, ptlUrl);
		response.setCharacterEncoding("UTF-8");
		PrintWriter writer = response.getWriter();
		writer.write(result);
		writer.close();
	}
}



上面的代码是判断web.xml里面的portal.url有没有赋值,如果为空就将prlUrl赋值为"http://localhost:8082/portal"

当代码走到

String result = PtlRedirector.getResponsePost(request, ptlUrl);

的时候,会将ptlUrl发送给PtlRedirector类进行处理

第三步:

是PtlRedirector类的处理过程

package com.company.portal;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Enumeration;

import javax.servlet.http.HttpServletRequest;

public class PtlRedirector {

	public static String getResponseGet(HttpServletRequest request,
			String baseUrl) {
		String param = concatParams(request);
		String url = baseUrl + param;
		String token = request.getHeader("token");
		String resourcePool = request.getHeader("resourcePool");
		String response = readResponseFromURL(url,token,resourcePool);
		return response;
	}

	public static String getResponsePost(HttpServletRequest request,
			String baseUrl) {
		String param = concatParams(request);
		String url = baseUrl + param;
		String json = readJSONString(request);
		String token,resourcePool;
		token = request.getHeader("token");
		resourcePool = request.getHeader("resourcePool");
		String response;
		if(token != null && resourcePool != null){
			response = sendPostHeader(url,token,resourcePool,json);
		}else{
			response = sendPost(url, json);			
		}
		return response;
	}

	private static String sendPostHeader(String url, String token,
			String resourcePool, String param) {

		PrintWriter out = null;
		BufferedReader in = null;
		String result = "";
		try {
			URL realUrl = new URL(url);
			// 打开和URL之间的连接
			URLConnection conn = realUrl.openConnection();
			conn.setRequestProperty("token", token);
			conn.setRequestProperty("resourcePool", resourcePool);
			// 设置通用的请求属性
			// 发送POST请求必须设置如下两行
			conn.setDoOutput(true);
			conn.setDoInput(true);
			// 获取URLConnection对象对应的输出流
			out = new PrintWriter(conn.getOutputStream());
			// 发送请求参数
			out.print(param);
			// flush输出流的缓冲
			out.flush();
			// 定义BufferedReader输入流来读取URL的响应
			in = new BufferedReader(
					new InputStreamReader(conn.getInputStream(), "utf-8"));
			String line;
			while ((line = in.readLine()) != null) {
				result += line;
			}
		} catch (Exception e) {
			System.out.println("发送 POST 请求出现异常!" + e);
			e.printStackTrace();
		}
		// 使用finally块来关闭输出流、输入流
		finally {
			try {
				if (out != null) {
					out.close();
				}
				if (in != null) {
					in.close();
				}
			} catch (IOException ex) {
				ex.printStackTrace();
			}
		}
		return result;
	}

	public static String readJSONString(HttpServletRequest request) {
		StringBuffer json = new StringBuffer();
		String line = null;
		try {
			BufferedReader reader = request.getReader();
			while ((line = reader.readLine()) != null) {
				json.append(line);
			}
		} catch (Exception e) {
			System.out.println(e.toString());
			return json.toString();
		}
		return json.toString();
	}

	@SuppressWarnings("rawtypes")
	private static String concatParams(HttpServletRequest request) {
		StringBuilder sb = new StringBuilder();
		Enumeration en = request.getParameterNames();
		while (en.hasMoreElements()) {
			String name = (String) en.nextElement();
			String value = request.getParameter(name).trim();
			if (value.length() == 0)
				continue;
			sb.append(value);
		}
		return sb.toString();
	}

	private static String readResponseFromURL(String url,String token,String resourcePool) {

		URL getUrl;
		HttpURLConnection connection = null;
		BufferedReader reader = null;

		StringBuilder result = new StringBuilder();

		try {
			getUrl = new URL(url);
			connection = (HttpURLConnection) getUrl.openConnection();
			connection.setRequestProperty("token", token);
			connection.setRequestProperty("resourcePool", resourcePool);
			connection.connect();
			if (connection.getResponseCode() == 200) {
				reader = new BufferedReader(new InputStreamReader(
						connection.getInputStream(), "utf-8"));// set charset to
				String lines;
				while ((lines = reader.readLine()) != null) {
					result.append(lines);
				}
			} else {
				reader = new BufferedReader(new InputStreamReader(
						connection.getErrorStream(), "utf-8"));// set charset to
				String lines;
				while ((lines = reader.readLine()) != null) {
					result.append(lines);
				}
			}
		} catch (Exception e) {
		} finally {
			try {
				if (reader != null) {
					reader.close();
				}
				if (connection != null) {
					connection.disconnect();
				}

			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return result.toString();
	}

	private static String sendPost(String url, String param) {

		PrintWriter out = null;
		BufferedReader in = null;
		String result = "";
		try {
			URL realUrl = new URL(url);
			// 打开和URL之间的连接
			URLConnection conn = realUrl.openConnection();
			// 设置通用的请求属性
			conn.setRequestProperty("accept", "*/*");
			conn.setRequestProperty("connection", "Keep-Alive");
			conn.setRequestProperty("user-agent",
					"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
			// 发送POST请求必须设置如下两行
			conn.setDoOutput(true);
			conn.setDoInput(true);
			// 获取URLConnection对象对应的输出流
			out = new PrintWriter(conn.getOutputStream());
			// 发送请求参数
			out.print(param);
			// flush输出流的缓冲
			out.flush();
			// 定义BufferedReader输入流来读取URL的响应
			in = new BufferedReader(
					new InputStreamReader(conn.getInputStream(), "utf-8"));
			String line;
			while ((line = in.readLine()) != null) {
				result += line;
			}
		} catch (Exception e) {
			System.out.println("发送 POST 请求出现异常!" + e);
			e.printStackTrace();
		}
		// 使用finally块来关闭输出流、输入流
		finally {
			try {
				if (out != null) {
					out.close();
				}
				if (in != null) {
					in.close();
				}
			} catch (IOException ex) {
				ex.printStackTrace();
			}
		}
		return result;
	}

}

上面的代码分别给出了带头信息的Post请求和不带头信息的Post请求的处理方法,同时给出不同请求方式Get和Post的带头信息的和不带头信息的处理方法,会将js里面请求的url变成所需要的url从而达到跨域访问的效果。