【发布时间】:2016-03-12 18:25:36
【问题描述】:
如何从运行在不同服务器上的 AngularJS 应用调用 Spring Boot REST api? 具体来说,如何修改以下代码来完成此操作?
我正在使用 the tutorial at this link 学习 Spring Boot。该应用程序的第一部分和第二部分运行完美。在part three of the tutorial (which is at this link) 中,我们将REST api 移动到不同的资源服务器,原型为localhost:9000。
本教程使用 groovy 制作资源服务器应用程序,但我正在尝试将其修改为 Java。
当我定义/home/username/workspacename/resource/src/main/java/com/example/ResourceApplication.java 时,我可以访问localhost:9000 的Web 服务,如下所示。
但是,在 localhost:8080 上运行的 AngularJS 应用程序无法从 localhost:9000 访问 Web 服务。当我然后添加CorsFilter.java 如下所示并使用kill $(lsof -t -i:9000) 和mvn spring-boot:run 重新启动服务时,我无法再查看localhost:9000 的数据,并且我仍然无法从应用程序访问Web 服务localhost:8080。
我没有对代码进行任何其他更改,我停在教程中创建CorsFilter.java 并重新启动应用程序的位置。 那么如何更改下面的代码以从localhost:9000 获取Web 服务,以便从localhost:8080 的gui 应用程序访问?
资源服务器中两个更改类的代码如下:
/home/username/workspacename/resource/src/main/java/com/example/ResourceApplication.java 是:
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@SpringBootApplication
@RestController
public class ResourceApplication {
@RequestMapping("/")
public Map<String,Object> home() {
Map<String,Object> model = new HashMap<String,Object>();
model.put("id", UUID.randomUUID().toString());
model.put("content", "Hello World");
return model;
}
public static void main(String[] args) {
SpringApplication.run(ResourceApplication.class, args);
}
}
/home/username/workspacename/resource/src/main/java/com/example/CorsFilter.java 是:
package com.example;
import java.io.IOException;
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.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.core.annotation.Order;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
class CorsFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
response.setHeader("Access-Control-Max-Age", "3600");
if (request.getMethod().equals("OPTIONS")) {
try {chain.doFilter(req, res);}
catch (IOException e) {e.printStackTrace();}
catch (ServletException e) {e.printStackTrace();}
}
else { }
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}
hello.js 文件在 GUI 应用程序中localhost:8080 的代码是:
angular.module('hello', [ 'ngRoute' ])
.config(function($routeProvider, $httpProvider) {
$routeProvider.when('/', {
templateUrl : 'home.html',
controller : 'home'
}).when('/login', {
templateUrl : 'login.html',
controller : 'navigation'
}).otherwise('/');
$httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';
})
.controller('home', function($scope, $http) {
$http.get('http://localhost:9000/').success(function(data) {
$scope.greeting = data;
})
})
.controller('navigation',
function($rootScope, $scope, $http, $location) {
var authenticate = function(credentials, callback) {
var headers = credentials ? {authorization : "Basic "
+ btoa(credentials.username + ":" + credentials.password)
} : {};
$http.get('user', {headers : headers}).success(function(data) {
if (data.name) {
$rootScope.authenticated = true;
} else {
$rootScope.authenticated = false;
}
callback && callback();
}).error(function() {
$rootScope.authenticated = false;
callback && callback();
});
}
authenticate();
$scope.credentials = {};
$scope.login = function() {
authenticate($scope.credentials, function() {
if ($rootScope.authenticated) {
$location.path("/");
$scope.error = false;
} else {
$location.path("/login");
$scope.error = true;
}
});
};
$scope.logout = function() {
$http.post('logout', {}).success(function() {
$rootScope.authenticated = false;
$location.path("/");
}).error(function(data) {
$rootScope.authenticated = false;
});
}
});
正在进行的研究:
按照@meriton 的要求,我在firefox 中打开了开发者工具,然后请求localhost:8080。当我放大到网络选项卡以获取 GET 请求的响应标头以调用嵌入在 localhost:8080 请求中的 localhost:9000 时,我得到了以下请求标头:
Access-Control-Allow-Headers: x-requested-with
Access-Control-Allow-Methods: POST, PUT, GET, OPTIONS, DELETE
Access-Control-Max-Age: 3600
Content-Length: 0
Date: Tue, 08 Dec 2015 00:41:01 GMT
Server: Apache-Coyote/1.1
access-control-allow-origin: *
并且Network选项卡中还显示了以下请求标头:
Host: localhost:9000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
X-Requested-With: XMLHttpRequest
Referer: http://localhost:8080/
Origin: http://localhost:8080
Connection: keep-alive
【问题讨论】:
-
“我无法再查看 localhost:9000 的数据”是什么意思?你有错误吗?如果是这样,什么错误?
-
@meriton 我只是得到一个白色的空白页。浏览器没有错误。我将使用开发人员工具查看这些日志中显示的内容。我还应该去哪里看?
-
开发者工具。具体来说,javascript 控制台,如果服务器响应异常,则网络选项卡。如果 javascript 控制台上没有错误,并且响应看起来有效,则必须调试发送 rest 请求并处理响应的代码。
-
@meriton 我刚刚在 Firefox 中调用了
localhost:9000,并打开了开发者工具。调试器选项卡显示no sources和no stack frames。当我从网络选项卡再次调用它时,日志列出了对/的调用,响应为 0kb。 -
什么是 HTTP 状态和响应的标头?也就是说,这听起来像是您的服务器行为不端。
标签: java angularjs spring spring-boot cors