Ajax访问Restful API跨域解决方案
发布时间:2020-12-16 01:52:53 所属栏目:百科 来源:网络整理
导读:最近开发API接口时,用Ajax调用远程服务上API的接口时,出现以下错误 : XMLHttpRequest cannot load http://192.168.1.101:8080/CDHAPI/bond/quote/minutely/1m/112188.SZ. No 'Access-Control-Allow-Origin' header is present on the requested resource.
|
最近开发API接口时,用Ajax调用远程服务上API的接口时,出现以下错误 :
XMLHttpRequest cannot load http://192.168.1.101:8080/CDHAPI/bond/quote/minutely/1m/112188.SZ. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access.产生此种问题是由于Ajax跨域限制而引起的问题。Access-Control-Allow-Origin是HTML5中定义的一种服务器端返回Response header,用来解决资源(比如字体)的跨域权限问题。它定义了该资源允许被哪个域引用,或者被所有域引用。 根据这个思路,在服务端返回时在响应体的添加Header,设置Access-Control-Allow-Origin允许可访问的域。具体工作如下: (1)写一个过滤器,在Reponse中Header中设置Access-Control-Allow-Origin:代码如下: package com.sumscope.cdh.api.interceptor;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
public class CrossFilter implements Filter {
private static final boolean debug = true;
private FilterConfig filterConfig = null;
public CrossFilter() {
super();
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
if (filterConfig != null) {
if (debug) {
log("CrossFilter:Initializing filter");
}
}
}
@Override
public String toString() {
if (filterConfig == null) {
return ("CrossFilter()");
}
StringBuffer sb = new StringBuffer("CrossFilter(");
sb.append(filterConfig);
sb.append(")");
return (sb.toString());
}
@Override
public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain) throws IOException,ServletException {
if (debug) {
log("CrossFilter:doFilter()");
}
if(response instanceof HttpServletResponse){
HttpServletResponse alteredResponse = ((HttpServletResponse)response);
// I need to find a way to make sure this only gets called on 200-300 http responses
// TODO: see above comment
addHeadersFor200Response(alteredResponse);
}
doBeforeProcessing(request,response);
Throwable problem = null;
try {
chain.doFilter(request,response);
} catch (Throwable t) {
// If an exception is thrown somewhere down the filter chain,// we still want to execute our after processing,and then
// rethrow the problem after that.
problem = t;
t.printStackTrace();
}
doAfterProcessing(request,response);
// If there was a problem,we want to rethrow it if it is
// a known type,otherwise log it.
if (problem != null) {
if (problem instanceof ServletException) {
throw (ServletException) problem;
}
if (problem instanceof IOException) {
throw (IOException) problem;
}
sendProcessingError(problem,response);
}
}
@Override
public void destroy() {
}
private void doBeforeProcessing(ServletRequest request,ServletResponse response)
throws IOException,ServletException {
if (debug) {
log("CrossFilter:DoBeforeProcessing");
}
}
private void doAfterProcessing(ServletRequest request,ServletException {
if (debug) {
log("CrossFilter:DoAfterProcessing");
}
}
private void addHeadersFor200Response(HttpServletResponse response){
//TODO: externalize the Allow-Origin
response.addHeader("Access-Control-Allow-Origin","*");
response.addHeader("Access-Control-Allow-Methods","POST,GET,OPTIONS,PUT,DELETE,HEAD");
response.addHeader("Access-Control-Allow-Headers","X-PINGOTHER,Origin,X-Requested-With,Content-Type,Accept");
response.addHeader("Access-Control-Max-Age","1728000");
}
private void sendProcessingError(Throwable t,ServletResponse response) {
String stackTrace = getStackTrace(t);
if (stackTrace != null && !stackTrace.equals("")) {
try {
response.setContentType("text/html");
PrintStream ps = new PrintStream(response.getOutputStream());
PrintWriter pw = new PrintWriter(ps);
pw.print("<html>n<head>n<title>Error</title>n</head>n<body>n"); //NOI18N
// PENDING! Localize this for next official release
pw.print("<h1>The resource did not process correctly</h1>n<pre>n");
pw.print(stackTrace);
pw.print("</pre></body>n</html>"); //NOI18N
pw.close();
ps.close();
response.getOutputStream().close();
} catch (Exception ex) {
}
} else {
try {
PrintStream ps = new PrintStream(response.getOutputStream());
t.printStackTrace(ps);
ps.close();
response.getOutputStream().close();
} catch (Exception ex) {
}
}
}
public static String getStackTrace(Throwable t) {
String stackTrace = null;
try {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
t.printStackTrace(pw);
pw.close();
sw.close();
stackTrace = sw.getBuffer().toString();
} catch (Exception ex) {
}
return stackTrace;
}
public void log(String msg) {
filterConfig.getServletContext().log(msg);
}
}
在Web.xml配置域名访问过滤器 <filter>
<filter-name>crossFilter</filter-name>
<filter-class>com.sumscope.cdh.api.interceptor.CrossFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>crossFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>ajax调用:
<html>
<meta charset="utf-8">
<script src="jquery.min.js"></script>
<script src="d3.min.js"></script>
<script src="techan.min.js"></script>
<style>
body {
font: 10px sans-serif;
}
.axis path,.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
text.symbol {
fill: #BBBBBB;
}
path {
fill: none;
stroke-width: 1;
}
path.candle {
stroke: #000000;
}
path.candle.body {
stroke-width: 0;
}
path.candle.up {
fill: #00AA00;
stroke: #00AA00;
}
path.candle.down {
fill: #FF0000;
stroke: #FF0000;
}
.close.annotation.up path {
fill: #00AA00;
}
path.volume {
fill: #DDDDDD;
}
.indicator-plot path.line {
fill: none;
stroke-width: 1;
}
.ma-0 path.line {
stroke: #1f77b4;
}
.ma-1 path.line {
stroke: #aec7e8;
}
.ma-2 path.line {
stroke: #ff7f0e;
}
button {
position: absolute;
right: 110px;
top: 25px;
}
path.macd {
stroke: #0000AA;
}
path.signal {
stroke: #FF9999;
}
path.zero {
stroke: #BBBBBB;
stroke-dasharray: 0;
stroke-opacity: 0.5;
}
path.difference {
fill: #BBBBBB;
opacity: 0.5;
}
path.rsi {
stroke: #000000;
}
path.overbought,path.oversold {
stroke: #FF9999;
stroke-dasharray: 5,5;
}
path.middle,path.zero {
stroke: #BBBBBB;
stroke-dasharray: 5,5;
}
.analysis path,.analysis circle {
stroke: blue;
stroke-width: 0.8;
}
.trendline circle {
stroke-width: 0;
display: none;
}
.mouSEOver .trendline path {
stroke-width: 1.2;
}
.mouSEOver .trendline circle {
stroke-width: 1;
display: inline;
}
.dragging .trendline path,.dragging .trendline circle {
stroke: darkblue;
}
.interaction path,.interaction circle {
pointer-events: all;
}
.interaction .body {
cursor: move;
}
.trendlines .interaction .start,.trendlines .interaction .end {
cursor: nwse-resize;
}
.supstance path {
stroke-dasharray: 2,2;
}
.supstances .interaction path {
pointer-events: all;
cursor: ns-resize;
}
.mouSEOver .supstance path {
stroke-width: 1.5;
}
.dragging .supstance path {
stroke: darkblue;
}
.crosshair {
cursor: crosshair;
}
.crosshair path.wire {
stroke: #DDDDDD;
stroke-dasharray: 1,1;
}
.crosshair .axisannotation path {
fill: #DDDDDD;
}
</style>
<body>
<div id="formQuote">
<input type="text" name="symbol" placeholder="Enter Symbol">
<input type="button" name="btnQuote" value="Get Quote" />
<select name="symbolList">
<option value=""></option>
<option value="110031.SH">110031.SH</option>
<option value="112188.SZ">112188.SZ</option>
</select>
</div>
</body>
<script>
var api_root = "http://<span style="font-family: Arial,Helvetica,sans-serif;">192.168.1.101</span>:8080/CDHAPI/bond";
var formQuote = $("#formQuote");
$.extend(formQuote,{
in_symbol: formQuote.find("input[name=symbol]"),symbol_list: formQuote.find("select[name=symbolList]"),selectSymbol: function() {
symbol = this.symbol_list.children("option:checked").val();
this.in_symbol.val(symbol);
},submit: function() {
symbol = $.trim(this.in_symbol.val());
if (!symbol.length) {
alert("Please input a Symbol!");
return false;
}
var url = api_root + "/quote/minutely/1m/" + symbol;
console.log(url);
this.showQuoteChart(url);
},showQuoteChart: function(url) {
var self = this;
//d3.csv("data.csv",function(error,data) {
d3.json(url,data) {
//d3.json("quote.json",data) {
var accessor = candlestick.accessor(),indicatorPreRoll = 0; // Don't show where indicators don't have data
console.log(data);
data = data.map(function(d) {
return {
/*
date: parseDate(d.Date),open: +d.Open,high: +d.High,low: +d.Low,close: +d.Close,volume: +d.Volume
*/
date: new Date(d.durationTime),open: +d.openCleanPrice,high: +d.highCleanPrice,low: +d.lowCleanPrice,close: +d.closeCleanPrice,volume: +d.volume
};
}).sort(function(a,b) { return d3.ascending(accessor.d(a),accessor.d(b)); });
x.domain(techan.scale.plot.time(data).domain());
y.domain(techan.scale.plot.ohlc(data.slice(indicatorPreRoll)).domain());
yPercent.domain(techan.scale.plot.percent(y,accessor(data[indicatorPreRoll])).domain());
yVolume.domain(techan.scale.plot.volume(data).domain());
svg.select("g.candlestick").datum(data).call(candlestick);
svg.select("g.close.annotation").datum([data[data.length-1]]).call(closeAnnotation);
svg.select("g.volume").datum(data).call(volume);
svg.select("g.sma.ma-0").datum(techan.indicator.sma().period(10)(data)).call(sma0);
svg.select("g.sma.ma-1").datum(techan.indicator.sma().period(20)(data)).call(sma1);
svg.select("g.ema.ma-2").datum(techan.indicator.ema().period(50)(data)).call(ema2);
svg.select("g.crosshair.ohlc").call(ohlcCrosshair).call(zoom);
var zoomable = x.zoomable();
zoomable.domain([indicatorPreRoll,data.length]); // Zoom in a little to hide indicator preroll
self.drawChart();
// Associate the zoom with the scale after a domain has been applied
zoom.x(zoomable).y(y);
zoomPercent.y(yPercent);
});
},resetChart: function() {
zoom.scale(1);
zoom.translate([0,0]);
this.drawChart();
},drawChart: function() {
zoomPercent.translate(zoom.translate());
zoomPercent.scale(zoom.scale());
svg.select("g.x.axis").call(xAxis);
svg.select("g.ohlc .axis").call(yAxis);
svg.select("g.volume.axis").call(volumeAxis);
svg.select("g.percent.axis").call(percentAxis);
// We know the data does not change,a simple refresh that does not perform data joins will suffice.
svg.select("g.candlestick").call(candlestick.refresh);
svg.select("g.close.annotation").call(closeAnnotation.refresh);
svg.select("g.volume").call(volume.refresh);
svg.select("g .sma.ma-0").call(sma0.refresh);
svg.select("g .sma.ma-1").call(sma1.refresh);
svg.select("g .ema.ma-2").call(ema2.refresh);
svg.select("g.crosshair.ohlc").call(ohlcCrosshair.refresh);
},initialize: function() {
var self = this;
this.find("input[name=btnQuote]").click(function(event) { self.submit(); });
this.symbol_list.on("change",function(event) { self.selectSymbol(); });
},});
formQuote.initialize();
/* Techanjs */
var dim = {
width: 960,height: 360,margin: { top: 20,right: 50,bottom: 30,left: 50 },ohlc: { height: 305 },};
dim.plot = {
width: dim.width - dim.margin.left - dim.margin.right,height: dim.height - dim.margin.top - dim.margin.bottom
};
var parseDate = d3.time.format("%d-%b-%y").parse;
var zoom = d3.behavior.zoom()
.on("zoom",formQuote.drawChart);
var zoomPercent = d3.behavior.zoom();
var x = techan.scale.financetime()
.range([0,dim.plot.width]);
var y = d3.scale.linear()
.range([dim.ohlc.height,0]);
var yPercent = y.copy(); // Same as y at this stage,will get a different domain later
var yVolume = d3.scale.linear()
.range([y(0),y(0.2)]);
var candlestick = techan.plot.candlestick()
.xScale(x)
.yScale(y);
var sma0 = techan.plot.sma()
.xScale(x)
.yScale(y);
var sma1 = techan.plot.sma()
.xScale(x)
.yScale(y);
var ema2 = techan.plot.ema()
.xScale(x)
.yScale(y);
var volume = techan.plot.volume()
.accessor(candlestick.accessor()) // Set the accessor to a ohlc accessor so we get highlighted bars
.xScale(x)
.yScale(yVolume);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var timeAnnotation = techan.plot.axisannotation()
.axis(xAxis)
.format(d3.time.format('%Y-%m-%d'))
.width(65)
.translate([0,dim.plot.height]);
var yAxis = d3.svg.axis()
.scale(y)
.orient("right");
var ohlcAnnotation = techan.plot.axisannotation()
.axis(yAxis)
.format(d3.format(',.2fs'))
.translate([x(1),0]);
var closeAnnotation = techan.plot.axisannotation()
.axis(yAxis)
.accessor(candlestick.accessor())
.format(d3.format(',0]);
var percentAxis = d3.svg.axis()
.scale(yPercent)
.orient("left")
.tickFormat(d3.format('+.1%'));
var percentAnnotation = techan.plot.axisannotation()
.axis(percentAxis);
var volumeAxis = d3.svg.axis()
.scale(yVolume)
.orient("right")
.ticks(3)
.tickFormat(d3.format(",.3s"));
var volumeAnnotation = techan.plot.axisannotation()
.axis(volumeAxis)
.width(35);
var ohlcCrosshair = techan.plot.crosshair()
.xScale(timeAnnotation.axis().scale())
.yScale(ohlcAnnotation.axis().scale())
.xAnnotation(timeAnnotation)
.yAnnotation([ohlcAnnotation,percentAnnotation,volumeAnnotation])
.verticalWireRange([0,dim.plot.height]);
var svg = d3.select("body").append("svg")
.attr("width",dim.width)
.attr("height",dim.height);
var defs = svg.append("defs");
defs.append("clipPath")
.attr("id","ohlcClip")
.append("rect")
.attr("x",0)
.attr("y",0)
.attr("width",dim.plot.width)
.attr("height",dim.ohlc.height);
svg = svg.append("g")
.attr("transform","translate(" + dim.margin.left + "," + dim.margin.top + ")");
svg.append('text')
.attr("class","symbol")
.attr("x",20)
.text("Facebook,Inc. (FB)");
svg.append("g")
.attr("class","x axis")
.attr("transform","translate(0," + dim.plot.height + ")");
var ohlcSelection = svg.append("g")
.attr("class","ohlc")
.attr("transform",0)");
ohlcSelection.append("g")
.attr("class","axis")
.attr("transform","translate(" + x(1) + ",0)")
.append("text")
.attr("transform","rotate(-90)")
.attr("y",-12)
.attr("dy",".71em")
.style("text-anchor","end")
.text("Price ($)");
ohlcSelection.append("g")
.attr("class","close annotation up");
ohlcSelection.append("g")
.attr("class","volume")
.attr("clip-path","url(#ohlcClip)");
ohlcSelection.append("g")
.attr("class","candlestick")
.attr("clip-path","indicator sma ma-0")
.attr("clip-path","indicator sma ma-1")
.attr("clip-path","indicator ema ma-2")
.attr("clip-path","percent axis");
ohlcSelection.append("g")
.attr("class","volume axis");
// Add trendlines and other interactions last to be above zoom pane
svg.append('g')
.attr("class","crosshair ohlc");
svg.append('g')
.attr("class","crosshair macd");
svg.append('g')
.attr("class","crosshair rsi");
</script>
</html> (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
