参考资料
https://blog.csdn.net/u011474078/article/details/81427579
https://www.cnblogs.com/xdp-gacl/category/629559.html
概述
WebService是一种跨编程语言和跨操作系统平台的远程调用技术。
WebService是什么?
基于Web的服务:服务器端整出一些资源让客户端应用访问(获取数据)
一个跨语言、跨平台的规范(抽象)
多个跨平台、跨语言的应用间通信整合的方案(实际)
为什么要用Web service?
web service能解决:
跨平台调用
跨语言调用
远程调用
什么时候使用web Service?
同一家公司的新旧应用之间
不同公司的应用之间
一些提供数据的内容聚合应用:天气预报、股票行情
适用场合
1、跨防火墙通信
2、应用程序集成
3、B2B集
4、软件和数据重用
不适用场合
1、单机应用程序
2、局域网的同构应用程序
WebService三个要素:SOAP, WSDL,UDDI
WebService采用HTTP协议传输数据,采用XML格式封装数据。
WebService务器端首先要通过一个WSDL文件来说明自己家里有啥服务可以对外调用,服务是什么(服务中有哪些方法,方法接受 的参数是什么,返回值是什么),服务的网络地址用哪个url地址表示,服务通过什么方式来调用。
辨析:HttpClient和WebService的区别和介绍:前者基于http协议,相当于模拟浏览器,后者基于soap协议,通过xml来交互数据。
WebService开发
WebService开发可以分为服务器端开发和客户端开发两个方面
服务端开发
把公司内部系统的业务方法发布成WebService服务,供远程合作单位和个人调用。(借助一些WebService框架可以很轻松地把自己的业务对象发布成WebService服务,Java方面的典型WebService框架包括:axis,xfire,cxf 等,java ee服务器通常也支持发布WebService服务,例如JBoss。)
客户端开发
调用别人发布的WebService服务,大多数人从事的开发都属于这个方面,例如,调用天气预报WebService服务。(使用厂商的WSDL2Java之类的工具生成静态调用的代理类代码;使用厂商提供的客户端编程API类;使用SUN公司早期标准的jax-rpc开发包;使用 SUN公司最新标准的jax-ws开发包。当然SUN已被ORACLE收购)
WebService 的工作调用原理
对客户端而言,我们给这各类WebService客户端API传递wsdl文件的url地址,这些API就会创建出底层的代理类,我调用 这些代理,就可以访问到webservice服务。代理类把客户端的方法调用变成soap格式的请求数据再通过HTTP协议发出去,并把接收到的soap 数据变成返回值返回。对服务端而言,各类WebService框架的本质就是一个大大的Servlet,当远程调用客户端给它通过http协议发送过来 soap格式的请求数据时,它分析这个数据,就知道要调用哪个java类的哪个方法,于是去查找或创建这个对象,并调用其方法,再把方法返回的结果包装成 soap格式的数据,通过http响应消息回给客户端。
WebService技术框架 -CXF
参考: cxf开发webservice流程 spring与cxf整合
Spring 4 集成Apache CXF开发JAX-RS Web Service(RESTful)(基于http协议)
1.添加cxfjar包依赖
<dependencies>
<!-- CXF -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>${cxf.version}</version>
</dependency>
<!-- 如果在tomcat或者其他servlet容器中发布服务,不需要引用cxf-rt-transports-http-jetty -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>${cxf.version}</version>
</dependency>
<!-- End CXF -->
</dependencies>
<!--jackson-->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-jaxrs</artifactId>
<version>${jackson.version}</version>
</dependency>
2.web.xml中配置cxf servlet
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/ws/*</url-pattern>
</servlet-mapping>
3.编写Restful接口及接口实现类
@Path("/userwsservice/")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public class UserWSService
{
@Autowired
private IUserService userService;
@GET
@Path("/users/{id}/")
public User getUser(@PathParam("id") String id)
{
Map<String, Object> param = new HashMap<String, Object>();
param.put("id", id);
List<User> userList = userService.query(param);
return userList.size() > 0 ? userList.get(0) : null;
}
@POST
@Path("/users/getall")
public List<User> getAllUsers()
{
List<User> userList = userService.query(new HashMap<String, Object>());
return userList;
}
}
4.application.xml中配置cxf命名空间和jaxrs:server
也可以在在WEB-INF文件夹下创建cxf-servlet.xml,然后在里面配置
<bean id="userWSService" class="cn.edu.hdu.wsdemo.wsservice.UserWSService"></bean>
<bean id="jsonProvider" class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
<jaxrs:server id="users" address="/apis">
<jaxrs:serviceBeans>
<ref bean="userWSService" />
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref bean='jsonProvider' />
</jaxrs:providers>
</jaxrs:server>
5.验证
执行maven命令:clean tomcat:run
启动成功后,浏览器输入:http://localhost:8080/wsdemo/ws
结果:
输入:http://localhost:8080/wsdemo/ws/apis?_wadl
6.使用CXF调用restful服务
(1)添加cxf 客户端依赖
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-client</artifactId>
<version>${cxf.version}</version>
</dependency>
(2)cxf 提供了三种 REST 客户端
第一种:JAX-RS 1.0 时代的客户端
package demo.ws.rest_cxf;
import java.util.ArrayList;
import java.util.List;
import org.apache.cxf.jaxrs.client.JAXRSClientFactory;
import org.codehaus.jackson.jaxrs.JacksonJsonProvider;
public class JAXRSClient {
public static void main(String[] args) {
String baseAddress = "http://localhost:8080/ws/rest";
List<Object> providerList = new ArrayList<Object>();
providerList.add(new JacksonJsonProvider());
ProductService productService =
JAXRSClientFactory.create(baseAddress, ProductService.class, providerList);
List<Product> productList = productService.retrieveAllProducts();
for (Product product : productList) {
System.out.println(product);
}
}
}
本质是使用 CXF 提供的 org.apache.cxf.jaxrs.client.JAXRSClientFactory 工厂类来创建 ProductService 代理对象,通过代理对象调用目标对象上的方法。客户端同样也需要使用 Provider,此时仍然使用了 Jackson 提供的 org.codehaus.jackson.jaxrs.JacksonJsonProvider。
第二种:JAX-RS 2.0 时代的客户端
package com.test.rest.client;
import java.util.List;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MediaType;
import org.codehaus.jackson.jaxrs.JacksonJsonProvider;
public class Client {
public static void main(String[] args) {
String baseAddress = "http://localhost:8080/ws/rest";
JacksonJsonProvider jsonProvider = new JacksonJsonProvider();
List productList = ClientBuilder.newClient().register(jsonProvider)
.target(baseAddress).path("/products")
.request(MediaType.APPLICATION_JSON).get(List.class);
for (Object product : productList) {
System.out.println(product);
}
}
}
在 JAX-RS 2.0 中提供了一个名为 javax.ws.rs.client.ClientBuilder 的工具类,可用于创建客户端并调用 REST 服务,显然这种方式比前一种要先进,因为在代码中不再依赖 CXF API 了。
如果想返回带有泛型的 List,那么就该使用如下方式。
JAX-RS 2.0 时代带有泛型的客户端
package com.test.rest.client;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MediaType;
import org.codehaus.jackson.jaxrs.JacksonJsonProvider;
import org.junit.Test;
import com.test.rest.bean.Product;
/**
* 返回带有泛型的数据
* @author Administrator
*
*/
public class Client1 {
String baseAddress = "http://localhost:8080/ws/rest";
JacksonJsonProvider jsonProvider = new JacksonJsonProvider();
@Test
public void retrieveAll() {
List<Product> productList = ClientBuilder.newClient().register(jsonProvider)
.target(baseAddress).path("/products")
.request(MediaType.APPLICATION_JSON).get(new GenericType<List<Product>>(){});
for (Product product : productList) {
System.out.println(product);
}
}
/**
* 该方法测试参数查询,
* 如果测试表单参数,则需要提交表单
*/
@Test
public void retrieveByName_param(){
List<Product> productList = ClientBuilder.newClient()
.register(jsonProvider)
.target(baseAddress)
.path("/products/name")
.queryParam("name", "iphone63")
.request(MediaType.APPLICATION_JSON)
.get(new GenericType<List<Product>>(){});
for (Product product : productList) {
System.out.println(product);
}
}
/**
* 添加数据
*/
@Test
public void create(){
Product product = new Product();
product.setName("iphone7");
product.setPrice(6000);
Product resultProduct = ClientBuilder.newClient()
.register(jsonProvider)
.target(baseAddress)
.path("/product")
.request(MediaType.APPLICATION_JSON)
.post(Entity.entity(product, MediaType.APPLICATION_JSON), new GenericType<Product>(){});
System.out.println(resultProduct);
retrieveAll();
}
/**
* 修改数据1
*/
@Test
public void update(){
Product product = new Product();
product.setId(1L);
product.setName("iphone6s");
product.setPrice(4000);
Product resultTarget = ClientBuilder.newClient()
.register(jsonProvider)
.target(baseAddress)
.path("/product")
.request(MediaType.APPLICATION_JSON)
.put(Entity.entity(product, MediaType.APPLICATION_JSON), new GenericType<Product>(){});
System.out.println(resultTarget);
System.out.println("==================");
retrieveAll();
}
/**
* 修改数据2
*/
@Test
public void update2(){
Map<String,Object> fieldParam = new HashMap<>();
fieldParam.put("name", "ipad mini");
fieldParam.put("price", 1999);
Product product = ClientBuilder.newClient()
.register(jsonProvider)
.target(baseAddress)
.path("/product/2")
.request(MediaType.APPLICATION_JSON)
.put(Entity.entity(fieldParam, MediaType.APPLICATION_JSON), new GenericType<Product>(){});
System.out.println(product);
System.out.println("===========================");
retrieveAll();
}
/**
* 路径参数
* 删除数据:根据id删除
*/
@Test
public void delete(){
Product product = ClientBuilder.newClient()
.register(jsonProvider)
.target(baseAddress)
.path("/product/1")
.request(MediaType.APPLICATION_JSON)
.delete(new GenericType<Product>(){});
System.out.println(product);
System.out.println("===============");
retrieveAll();
}
/**
* 查询参数
* 删除数据:根据id删除
*/
@Test
public void delete_param(){
Product product = ClientBuilder.newClient()
.register(jsonProvider)
.target(baseAddress)
.path("/product")
.queryParam("id", 2L)
.request(MediaType.APPLICATION_JSON)
.delete(new GenericType<Product>(){});
System.out.println(product);
System.out.println("=================");
retrieveAll();
}
}
第三种:通用的WebClient客户端
package com.test.rest.client;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.core.MediaType;
import org.apache.cxf.jaxrs.client.WebClient;
import org.codehaus.jackson.jaxrs.JacksonJsonProvider;
/**
* 通用客户端WebClient的实现
*
* @author Administrator
*
*/
public class Client3 {
public static void main(String[] args) {
String baseAddress = "http://localhost:8080/ws/rest";
List<Object> providerList = new ArrayList<Object>();
providerList.add(new JacksonJsonProvider());
List productList = WebClient.create(baseAddress, providerList)
.path("/products").accept(MediaType.APPLICATION_JSON)
.get(List.class);
for(Object product : productList){
System.out.println(product);
}
}
}
CXF 还提供了一种更为简洁的方式,使用 org.apache.cxf.jaxrs.client.WebClient 来调用 REST 服务,这种方式在代码层面上还是相当简洁的。
如果想返回带有泛型的 List,那么可以使用以下代码片段:
List<Product> productList = WebClient.create(baseAddress, providerList)
.path("/products").accept(MediaType.APPLICATION_JSON)
.get(new GenericType<List<Product>>(){});
[spring mvc restful 与cxf restful]
1.Spring MVC 原生支持构建restful web api,就是楼主说的restful web service(严格说来不算web service,不满足web service的三要素)
2.CXF可以实现restful web api,也可以实现传统web service. 但是cxf并不依赖spring mvc/spring
如果已经使用了spring mvc,也已经能够实现restful web api. 如果你需要实现传统ws,可以集成cxf.否则确实没有必要. 如果你不使用spring mvc,也没有一个合适的实现了 restful mvc 实现,可以考虑使用cxf 。
[拓展1-JAX-RS]
采用jAX-RS注解:它是Java提供用于开发RESTful Web服务基于注解(annotation)的API。JAX-RS旨在定义一个统一的规范,使得Java程序员可以使用一套固定的接口来开发REST应用,避免了依赖第三方框架。同时JAX-RS使用POJO编程模型和基于注解的配置并集成JAXB,可以有效缩短REST应用的开发周期。JAX-RS只定义RESTful API,具体实现由第三方提供,如Jersey美[ˈdʒɜ:rzi]、Apache CXF等。
JAX-RS常用注解:
@Path:标注资源类或方法的相对路径。
@GET、@PUT、@POST、@DELETE:标注方法的HTTP请求类型。
@Produces:标注返回的MIME媒体类型。 @Produces({ javax.ws.rs.core.MediaType.APPLICATION_XML, javax.ws.rs.core.MediaType.APPLICATION_JSON })
@Consumes:标注可接受请求的MIME媒体类型。
@PathParam、@QueryParam、@HeaderParam、@CookieParam、@MatrixParam、@FormParam:标注方法的参数来自于HTTP请求的位置。@PathParam来自于URL的路径,@QueryParam来自于URL的查询参数,@HeaderParam来自于HTTP请求的头信息,@CookieParam来自于HTTP请求的Cookie。
[扩展2-规范的rest ful接口实例]
转:https://www.cnblogs.com/duanxz/p/3508983.html
/**
* 图书馆服务
*
*/
@Path("/library")
@Produces("text/xml")
public class LibraryService {
private Map<String, Book> books = new HashMap<String, Book>();
public LibraryService() {
// init();
}
/**
* 获取
*
* @param id
* 索引
* @return 书
*/
@GET
@Path("/books/{id}/")
public Book getBook(@PathParam("id") String id) {
return books.get(id);
}
/**
* 更新
*
* @param book
* @return
*/
@PUT
@Path("/books/")
public Response updateBook(Book book) {
Response r;
if (book == null) {
r = Response.noContent().build();
return r;
}
String id = book.getId();
Book b = books.get(id);
if (b != null) {
books.put(id, book);
r = Response.ok(true, MediaType.TEXT_PLAIN).build();
} else {
r = Response.notModified().build();
}
return r;
}
/**
* 添加
*
* @param book
* @return
*/
@POST
@Path("/books/")
public Response addBook(Book book) {
Response r;
if (book == null) {
r = Response.notModified().build();
} else {
books.put(book.getId(), book);
r = Response.ok(true, MediaType.TEXT_PLAIN).build();
}
return r;
}
/**
* 删除
*
* @param book
* @return
*/
@DELETE
@Path("/books/{id}/")
public Response deleteBook(@PathParam("id") String id) {
Response r;
Book book = books.get(id);
if (book == null) {
r = Response.notModified("id不存在").build();
} else {
books.remove(id);
r = Response.ok(book, MediaType.APPLICATION_XML).build();
}
return r;
}
/**
* 初始化,在图书馆里加几本书
*/
private void init() {
}
}
[拓展3-spring mvc实现Restful]
参考:前后端分离springmvc和RESTful理解
核心:spring4以前:@ResponseBody spring4.0以后@RestController 编写restful; 处理安全问题,CORS技术
Spring 集成Apache CXF开发JAX-WS Web Service(基于soap协议)
参考:https://www.cnblogs.com/xdp-gacl/category/629559.html
开发流程:
1.定义WS终端接口
2.发布WS
3.生成客户端代码调用WS
一、cxf发布服务的类
用两个不同的类发布应用:
a. ServerFactoryBean – FacotryBean
b. JaxWsServerFactoryBean(建议使用此类)
服务端与客户端类的使用映射关系如下图所示:
二、使用ServerFactoryBean发布标准的webservice服务
下载cxf安装包apache-cxf-2.4.2,里面lib下jar包以供项目使用。
1.服务端
a.新建web项目,加入cxf的jar包
b.定义webservice的接口
package com.wp.service;
import javax.jws.WebService;
@WebService
public interface HelloWs {
public String sayHello(String name);
}
c.定义webservice接口的实现类
package com.wp.service;
public class HelloWsImpl implements HelloWs {
@Override
public String sayHello(String name) {
return "hello" + name;
}
}
d.发布webservice服务
package com.wp.service;
import org.apache.cxf.frontend.ServerFactoryBean;
public class Server {
public static void main(String[] args) {
ServerFactoryBean sfb = new ServerFactoryBean();
//1.服务提供者实现的接口
sfb.setServiceClass(HelloWs.class);
//2.指定访问路径
sfb.setAddress("http://localhost:9090/ws");
//3.指定服务实现类
sfb.setServiceBean(new HelloWsImpl());
//4.发布
sfb.create();
System.out.println("发布成功...");
}
}
2.客户端
a.使用wsdl2java生成客户端代码调用服务
b.使用ClientProxyFactoryBean类调用service服务
客户端必须加入cxf的jar包
浏览器访问http://localhost:9090/ws?wsdl ,查看service和operation
1) 不同项目中调用
package com.wp.test;
import com.wp.client.HelloWs;
import com.wp.client.HelloWsPortType;
public class Client {
public static void main(String[] args) {
HelloWs hw = new HelloWs();
HelloWsPortType h = hw.getHelloWsPort();
String result = h.sayHello("小强");
System.out.println(result);
}
}
2) 在同一项目中调用
package com.wp.service;
import org.apache.cxf.frontend.ClientProxyFactoryBean;
public class Client {
public static void main(String[] args) {
ClientProxyFactoryBean cfb = new ClientProxyFactoryBean();
cfb.setAddress("http://localhost:9090/ws");
cfb.setServiceClass(HelloWs.class);
HelloWs hw = (HelloWs) cfb.create();
System.out.println(hw.sayHello("明明"));
}
}
类似的例子在apache-cxf-2.6.2安装包下的samples中,开发的时候可以查看
三、使用JaxWsServerFactoryBean类发布服务
1.服务端
package com.wp.service;
import javax.jws.WebParam;
import javax.jws.WebService;
@WebService
public interface HelloWs {
public String sayHello(@WebParam(name="text") String text);
}
package com.wp.service;
import javax.jws.WebService;
@WebService(endpointInterface = "com.wp.service.HelloWs")
public class HelloWsImpl implements HelloWs {
@Override
public String sayHello(String name) {
return "hello " + name;
}
}
package com.wp.service;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;
public class Server {
public static void main(String[] args) {
JaxWsServerFactoryBean jsfb = new JaxWsServerFactoryBean();
//1.服务提供者实现的接口
jsfb.setServiceClass(HelloWs.class);
//2.指定访问路径
jsfb.setAddress("http://localhost:9090/ws");
//3.指定服务实现类
jsfb.setServiceBean(new HelloWsImpl());
//jsfb.getInInterceptors().add(new LoggingInInterceptor());
//jsfb.getOutInterceptors().add(new LoggingOutInterceptor());
//4.发布
jsfb.create();
System.out.println("发布成功...");
}
}
2.客户端
生成客户端代码:
a.在不同项目中
package com.wp.test;
import org.apache.cxf.frontend.ClientProxyFactoryBean;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import com.wp.client.HelloWs;
public class Client {
public static void main(String[] args) {
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
// factory.getInInterceptors().add(new LoggingInInterceptor());
// factory.getOutInterceptors().add(new LoggingOutInterceptor());
factory.setAddress("http://localhost:9090/ws");
HelloWs client = factory.create(HelloWs.class);
System.out.println(client.sayHello("World"));
}
}
b.在同一项目中
package com.wp.service;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
public class Client {
public static void main(String[] args) {
JaxWsProxyFactoryBean bean = new JaxWsProxyFactoryBean();
bean.setAddress("http://localhost:9090/ws");
bean.setServiceClass(HelloWs.class);
HelloWs hw = (HelloWs) bean.create();
System.out.println(hw.sayHello("www"));
}
}
补充:CORS解决ajax跨域调用API问题
cors相比jsonp、改document.domain = ‘跨域地址’灵活简单
比如,前端应用为静态站点且部署在http://web.xxx.com域下,后端应用发布REST API并部署在http://api.xxx.com域下,如何使前端应用通过AJAX跨域访问后端应用呢?这需要使用到CORS技术来实现,这也是目前最好的解决方案了。
[CORS全称为Cross Origin Resource Sharing(跨域资源共享),服务端只需添加相关响应头信息,即可实现客户端发出AJAX跨域请求。]
CORS技术非常简单,易于实现,目前绝大多数浏览器均已支持该技术(IE8浏览器也支持了),服务端可通过任何编程语言来实现,只要能将CORS响应头写入response对象中即可。
通过CORS技术实现AJAX跨域访问基本实现如下:
1.编写一个Filter添加CORS响应头
这个FIlter用于过滤所有的HTTP请求,并将CORS响应头写入response对象中,代码如下:
public class CorsFilter implements Filter {
private String allowOrigin;
private String allowMethods;
private String allowCredentials;
private String allowHeaders;
private String exposeHeaders;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
allowOrigin = filterConfig.getInitParameter("allowOrigin");
allowMethods = filterConfig.getInitParameter("allowMethods");
allowCredentials = filterConfig.getInitParameter("allowCredentials");
allowHeaders = filterConfig.getInitParameter("allowHeaders");
exposeHeaders = filterConfig.getInitParameter("exposeHeaders");
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
if (StringUtil.isNotEmpty(allowOrigin)) {
List<String> allowOriginList = Arrays.asList(allowOrigin.split(","));
if (CollectionUtil.isNotEmpty(allowOriginList)) {
String currentOrigin = request.getHeader("Origin");
if (allowOriginList.contains(currentOrigin)) {
response.setHeader("Access-Control-Allow-Origin", currentOrigin);
}
}
}
if (StringUtil.isNotEmpty(allowMethods)) {
response.setHeader("Access-Control-Allow-Methods", allowMethods);
}
if (StringUtil.isNotEmpty(allowCredentials)) {
response.setHeader("Access-Control-Allow-Credentials", allowCredentials);
}
if (StringUtil.isNotEmpty(allowHeaders)) {
response.setHeader("Access-Control-Allow-Headers", allowHeaders);
}
if (StringUtil.isNotEmpty(exposeHeaders)) {
response.setHeader("Access-Control-Expose-Headers", exposeHeaders);
}
chain.doFilter(req, res);
}
@Override
public void destroy() {
}
}
以上CorsFilter将从web.xml中读取相关Filter初始化参数,并将在处理HTTP请求时将这些参数写入对应的CORS响应头中,下面大致描述一下这些CORS响应头的意义:
- Access-Control-Allow-Origin:允许访问的客户端域名,例如:http://web.xxx.com,若为*,则表示从任意域都能访问,即不做任何限制。
- Access-Control-Allow-Methods:允许访问的方法名,多个方法名用逗号分割,例如:GET,POST,PUT,DELETE,OPTIONS。
- Access-Control-Allow-Credentials:是否允许请求带有验证信息,若要获取客户端域下的cookie时,需要将其设置为true。
- Access-Control-Allow-Headers:允许服务端访问的客户端请求头,多个请求头用逗号分割,例如:Content-Type。
- Access-Control-Expose-Headers:允许客户端访问的服务端响应头,多个响应头用逗号分割。
这里有一个值得注意的响应头:Access-Control-Allow-Origin。该响应头用来记录可以访问该资源的域。在接收到服务端响应后,浏览器将会查看响应中是否包含Access-Control-Allow-Origin响应头。如果该响应头存在,那么浏览器会分析该响应头中所标示的内容。如果其包含了当前页面所在的域,那么浏览器就将知道这是一个被允许的跨域访问,从而不再根据Same-origin Policy来限制用户对该数据的访问。
需要注意的是,CORS规范中定义Access-Control-Allow-Origin只允许两种取值,要么为*,要么为具体的域名,也就是说,不支持同时配置多个域名。为了解决跨多个域的问题,需要在代码中做一些处理,这里将Filter初始化参数作为一个域名的集合(用逗号分隔),只需从当前请求中获取Origin请求头,就知道是从哪个域中发出的请求,若该请求在以上允许的域名集合中,则将其放入Access-Control-Allow-Origin响应头,这样跨多个域的问题就轻松解决了。
2.在web.xml中配置CorsFilter:
<filter>
<filter-name>corsFilter</filter-name>
<filter-class>com.xxx.api.cors.CorsFilter</filter-class>
<init-param>
<param-name>allowOrigin</param-name>
<param-value>http://web.xxx.com</param-value>
</init-param>
<init-param>
<param-name>allowMethods</param-name>
<param-value>GET,POST,PUT,DELETE,OPTIONS</param-value>
</init-param>
<init-param>
<param-name>allowCredentials</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>allowHeaders</param-name>
<param-value>Content-Type</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>corsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
完成以上过程即可实现AJAX跨域功能了。
参考:https://www.cnblogs.com/loveis715/p/4592246.html