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> (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |