Angular-Ionic调用Java服务端DELETE接口被CORS拦截问题求助
DELETE请求跨域(CORS)报错排查
问题背景
- 前端基于Angular-Ionic开发,运行地址为
http://localhost:8100 - 后端为自研Java HTTP服务,运行地址为
http://localhost:8080 - 故障现象:调用DELETE类型接口删除用户时触发CORS拦截,禁用浏览器CORS校验后接口可正常执行,确认业务逻辑本身无异常,需要实现普通用户无需修改浏览器配置即可正常访问的效果。
现有实现代码
前端请求逻辑
console.log('User Management Service Delete User()'); const myParams = new HttpParams().set('id', this.cookieService.get('AccessToken')); console.log(myParams); return this.http.delete(this.endpoint + 'users/delete', { params: myParams});
逻辑说明:从cookie中读取访问令牌作为id参数,发起DELETE请求到后端删除接口。
后端接口逻辑
public int serveUserDelete(HTTPServer.Request req, HTTPServer.Response resp) throws IOException { Map<String, String> params = req.getParams(); String response; String paramvalue; String accessToken; resp.getHeaders().add("Content-Type", "application/json"); resp.getHeaders().add("Access-Control-Allow-Origin", "*"); resp.getHeaders().add("Access-Control-Allow-Headers", "*"); resp.getHeaders().add("Access-Control-Allow-Credentials", "true"); resp.getHeaders().add("id", "*"); resp.getHeaders().add("Access-Control-Allow-Methods", "OPTIONS, DELETE, POST, GET, PATCH, PUT"); response = ""; // 从参数中读取id值 if (params.containsKey("id")) { accessToken = params.get("id"); System.out.println(accessToken); } else { accessToken = null; } response = um.userDelete(accessToken); resp.send(200, response); return 0; }
代码中所有CORS相关响应头为排查故障过程中陆续添加的配置。
报错信息
Access to XMLHttpRequest at 'http://localhost:8080/umyServerUrl/users/delete?id=u@Yy0NZPLx%266HxYNF%23tv' from origin 'http://localhost:8100' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
报错核心:浏览器发送的预检(OPTIONS)请求响应未通过CORS校验,响应中不存在Access-Control-Allow-Origin头。
控制台调试输出
请求参数打印
HttpParams {updates: Array(1), cloneFrom: HttpParams, encoder: HttpUrlEncodingCodec, map: null} cloneFrom: nullencoder: HttpUrlEncodingCodec {}[[Prototype]]: Objectconstructor: class HttpUrlEncodingCodecdecodeKey: ƒ decodeKey(key)decodeValue: ƒ decodeValue(value)encodeKey: ƒ encodeKey(key)encodeValue: ƒ encodeValue(value)[[Prototype]]: Objectmap: Map(1)[[Entries]]0: {"id" => Array(1)} key: "id" value: ['hTxYusBwuB7pbUUCkW9E']size: 1[[Prototype]]: Mapupdates: null[[Prototype]]: Object user-management.service.ts:35
返回对象打印
Observable {_isScalar: false, source: Observable, operator: MapOperator} operator: MapOperator project: res => res.body length: 1 name: "" arguments: (...) caller: (...) [[FunctionLocation]]: http.mjs:1300 [[Prototype]]: ƒ () [[Scopes]]: Scopes[2] thisArg: undefined [[Prototype]]: Object call: ƒ call(subscriber, source) constructor: class MapOperator [[Prototype]]: Object source: Observable operator: FilterOperator {thisArg: undefined, predicate: ƒ} source: Observable {_isScalar: false, source: Observable, operator: MergeMapOperator} _isScalar: false [[Prototype]]: Object _isScalar: false [[Prototype]]: Object
故障原因与修复方法
核心原因
DELETE属于非简单请求,浏览器会在实际发送DELETE请求前,先发送一个OPTIONS方法的预检请求,校验服务端是否允许跨域访问。当前后端仅在处理DELETE请求的serveUserDelete方法中添加了CORS响应头,没有针对OPTIONS请求做单独处理,预检请求到达服务端后拿不到合法的CORS响应头,直接被浏览器拦截。
另外现有CORS配置存在规则冲突:Access-Control-Allow-Credentials设为true时,Access-Control-Allow-Origin不允许使用通配符*,就算处理了OPTIONS请求,后续实际请求也会因为这个规则冲突被拦截。
修复步骤
- 给服务端新增OPTIONS方法的路由处理:针对
/users/delete路径的OPTIONS请求,单独返回200状态码,同时携带全套CORS响应头,不需要执行删除用户的业务逻辑。如果服务端接口较多,可以写一个全局的CORS过滤器,所有请求进入业务逻辑前先判断是否是OPTIONS请求,是则直接返回CORS头和200状态码。 - 修正CORS配置冲突:将
Access-Control-Allow-Origin的值从*改为动态读取请求头中的Origin字段值直接返回;Access-Control-Allow-Headers不要用*,明确配置允许的请求头,比如Content-Type, Authorization, id即可。 - 删除无效配置:
resp.getHeaders().add("id", "*")不属于标准CORS响应头,没有实际作用,可以直接移除。
内容的提问来源于stack exchange,提问作者Lytrix
相关产品推荐
相关产品推荐

