Cross-Origin Resource Sharing 跨域资源共享研究心得

部署运行你感兴趣的模型镜像

现在的项目,要提供一个对外的接口给手机端浏览器访问,由于同域安全策略,浏览器会默认禁止js ajax对该跨域接口的访问,原本以为不能访问的。于是用chrome作为测试的浏览器,跨域访问该接口,发现实际上发送了一个http method为 options的请求到服务端,而请求中没有带上发送的body内容,反而有几个特殊的报文头添加到了http header中,

Request Method:OPTIONS

Request Headersview source
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:zh-CN,zh;q=0.8
Access-Control-Request-Headers:b, a, content-type
Access-Control-Request-Method:DELETE
Connection:keep-alive
Host:localhost:8080
Origin:http://10.8.186.36:8080
Referer:http://10.8.186.36:8080/ajax/test.html
User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36

通过在网上查找Access-Control-Request-Method ,发现了 Cross-Origin Resource Sharing 跨域资源共享,这个w3c 新标准,http://www.w3.org/TR/access-control
通过对该协议的了解了,发现,只要在options 请求的返回响应中,按照该标准进行验证,添加对应的resp header,
CORS最早的标准2008年发布,更新了多次,最新的标准是2014年发布,但是变化不大。andorid,ios浏览器都用的是开源 webkit核心,对这些标准的支持较好

分析该请求
request请求中多了
Access-Control-Request-Method:DELETE ,意思是,有一个DELETE http 请求申请通过
Access-Control-Request-Headers:b, a, content-type 意思是,该请求中带有不符合的 http标准的header头,b, a, content-type (在chrome 中有这个content-type,firefox却未出现,两浏览器准则有点不一样啊)

CORS response Header

通过CORS标准可以让该请求通过,
其中 Access-Control-Allow-Origin ,代表可以通过验证得域名
Access-Control-Allow-Credentials,true,false 允许携带用户认证凭据,(也就是是否允许cookie)
Access-Control-Allow-Methods , 允许通过的METHOD (DELETE , PUT,POST,GET,OPTIONS,)
Access-Control-Allow-Headers , 允许通过的requestHeader 用逗号隔开
Access-Control-Max-Age ,delta-seconds ,单位秒,该验证有效期限,超过期限,会重新发送(关闭chrome浏览器,重新打开该浏览器,也重发)
Access-Control-Expose-Headers,允许脚本访问的返回头,请求成功后,脚本可以在XMLHttpRequest中访问这些头的信息(貌似webkit没有实现这个)

通过CORS 规范,在对应servlet中 的 doOptions 方法下,返回如下,就可以通过CORS验证

<!DOCTYPE html>
<html>
  <head>
    <title>test.html</title>
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="this is my page">
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <script type="text/javascript" src="jquery-2.1.3.js"></script>
    <script type="text/javascript">
        var _url= "http://10.8.186.36:8080/ajax/test";
        function sendHttp(){
            var url = _url+"?t="+new Date().getTime();
            $.ajax({
                url:url,
                method:"PUT",
                data:{a:1},
                success:function(data){
                    document.getElementById("show").innerHTML = data.time;
                },
                error:function(){
                    document.getElementById("show").innerHTML = 'error';
                }
            })
        }
    </script>
  </head>

  <body>
    <form action="">
        <textarea id="send" rows="10" cols="50" id="test"></textarea> <br/>
        <input id="sendBtn" type="button" value="提交" onclick="sendHttp();"/>
        <input type="reset" value="重置" /><br/>
        <textarea id="show" rows="10" cols="50" ></textarea><br/>
    </form>
  </body>
</html>
package com;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Enumeration;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class Test extends HttpServlet{

    private static final long serialVersionUID = 7853578899281716909L;

    public void doService(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {
        Enumeration en = req.getHeaderNames();
        while(en.hasMoreElements()){
            String name = (String) en.nextElement();
            System.out.println(name+"ďźš" + req.getHeader(name));
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String time = sdf.format(Calendar.getInstance().getTime());
        String data = "{\"time\":"+time+"}";

        resp.addHeader("Access-Control-Allow-Origin", "*");
        resp.addHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS,PUT,DELETE,HEAD");
        resp.addHeader("Access-Control-Allow-Headers", "a,b,content-type");
        resp.addHeader("Access-Control-Max-Age", "3600000");
        resp.addHeader("Access-Control-Allow-Credentials", "true");

        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("application/json;charset=utf-8");
        resp.getWriter().write(data);
        System.out.println("===================");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        System.out.println("get");
        doService(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        System.out.println("post");
        doService(req, resp);
    }


    @Override
    protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        System.out.println("Options");
        resp.addHeader("Access-Control-Allow-Origin", "*");
        resp.addHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS,PUT,DELETE,HEAD");
        resp.addHeader("Access-Control-Allow-Headers", "a,b,content-type");
        resp.addHeader("Access-Control-Max-Age", "3600000");
        resp.addHeader("Access-Control-Allow-Credentials", "true");
    }

    @Override
    protected void doPut(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        System.out.println("put");
        doService(req, resp);
    }

    @Override
    protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        System.out.println("delete");
        doService(req, resp);
    }


    @Override
    protected void doHead(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        System.out.println("head");
        doService(req, resp);
    }

}
Response Headersview source
Access-Control-Allow-Headers:a,b
Access-Control-Allow-Methods:POST,GET,OPTIONS,PUT,DELETE
Access-Control-Allow-Origin:*
Access-Control-Max-Age:300
Content-Length:0
Date:Fri, 10 Apr 2015 07:17:21 GMT
Server:Apache-Coyote/1.1

Access-Control-Allow-Headers:a,b 可以通过的自定义的头部 大小写不敏感
Access-Control-Allow-Methods:POST,GET,OPTIONS,PUT,DELETE 可以通过访问的HTTP方法
Access-Control-Allow-Origin:*
Access-Control-Max-Age:300 失效时间

options请求成功之后,浏览器判断服务器验证通过,会紧接着又触发了一次实际的请求,
其中 POST ,GET 并不会发送OPTIONS请求,

您可能感兴趣的与本文相关的镜像

GPT-oss:20b

GPT-oss:20b

图文对话
Gpt-oss

GPT OSS 是OpenAI 推出的重量级开放模型,面向强推理、智能体任务以及多样化开发场景

<think> 首先,用户的问题是:"我想查找后端使用CORSCross-origin resource sharing)解决问题的方法"。用户要求我回答后端使用CORS解决问题的方法。 我需要参考提供的引用,这些引用来自站内引用,包括[^1], [^2], [^3], [^4]。 - 引用[^1] 讨论了CORS基础原理,包括漏洞利用和预防措施。它提到正确配置请求。 - 引用[^2] 具体展示了如何在SpringBoot中使用CORS来解决前后端分离的问题,包括前端代码和后端实现代码。 - 引用[^3] 解释了CORS的工作原理,强调它是浏览器和服务器共同支持的,并且服务器是实现的关键。 - 引用[^4] 简要介绍了CORS作为访问技术,对比了其他方法。 用户的问题焦点是后端使用CORS解决问题的方法。所以,我应该从后端角度解释如何实现CORS。 从引用中提取关键点: - 从[^3]:CORS需要服务器实现CORS接口。浏览器自动处理,但服务器必须配置响应头来允许请求。 - 从[^2]:具体例子在SpringBoot中,后端可以通过添加CORS配置来解决。后端代码示例展示了如何设置响应头。 - 从[^1]:正确配置CORS包括只允许受信任的站点,避免空源等。 现在,结构化我的回答: 1. **解释CORS是什么**:简要说明CORS是浏览器机制,允许请求,但需要服务器设置响应头。 2. **后端实现方法**:详细描述后端如何设置响应头。 - 关键响应头: - `Access-Control-Allow-Origin`: 指定允许的源(如 `*` 或具体名)。 - `Access-Control-Allow-Methods`: 指定允许的HTTP方法(如 GET, POST)。 - `Access-Control-Allow-Headers`: 指定允许的请求头。 - `Access-Control-Allow-Credentials`: 指示是否允许发送凭据(如 cookies)。 3. **具体示例**:参考[^2],展示SpringBoot中的实现。例如,在Java中使用注解或配置类。 - 在[^2]中,后端代码通过设置响应头来实现。具体代码可能涉及添加 `@CrossOrigin` 注解或配置过滤器。 4. **一般步骤**:无论使用什么技术栈,后端都需要: - 在响应中添加必要的CORS头。 - 处理预检请求(OPTIONS方法),因为浏览器在发送实际请求前可能发送预检请求。 5. **最佳实践**:参考[^1],确保安全配置: - 不要使用通配符 `*` 在生产环境,除非必要。 - 只允许特定的可信名。 - 避免将 `null` 列入白名单。 - 在内部网络中也避免使用通配符。 6. **引用来源**:在回答中使用引用标识如[^1], [^2]等,自然添加在段落末尾。 回答结构: - 用中文回答。 - 保持清晰,逐步解释。 - 使用内联数学表达式如 $...$ 如果涉及公式,但这里可能不涉及数学,所以可能不需要。 - 独立公式如果需要,但同样,这里可能不需要。 - 生成相关问题在末尾。 最后,生成相关问题: - 基于主题,如CORS的其他方面、常见错误、与其他方法的比较等。 大纲响应: 1. **引言**:解释CORS及其作用。 2. **后端实现方法**: - 设置响应头。 - 处理预检请求。 - 框架具体示例(如SpringBoot)。 3. **安全注意事项**。 4. **总结**。 5. **相关问题**。 确保回答真实可靠,基于引用。 </think> ### 后端使用CORS解决问题的方法 资源共享CORSCross-Origin Resource Sharing)是浏览器的一种安全机制,用于限制不同源(协议、名、端口)之间的资源访问。如果未经正确配置,浏览器会阻止请求(如前端应用在 `http://localhost:3000` 访问后端 `http://api.example.com`),导致常见错误如“CORS policy”问题。CORS的核心在于**后端服务器设置响应头**来显式允许特定源的访问,而浏览器会自动处理这些头信息。以下从后端角度分步说明实现方法,参考了站内提供的引用内容。 #### 1. **CORS的基本工作原理** CORS依赖于HTTP响应头来控制请求。浏览器在发送请求时,会自动添加 `Origin` 头(如 `Origin: http://localhost:3000`),后端需在响应中返回特定的CORS头来授权该请求。关键点包括: - **简单请求**:对于GET、HEAD或POST(且Content-Type为 `application/x-www-form-urlencoded`、`multipart/form-data` 或 `text/plain`),浏览器直接发送请求,后端只需设置 `Access-Control-Allow-Origin`。 - **预检请求(Preflight)**:对于非简单请求(如PUT、DELETE或自定义头),浏览器先发送OPTIONS方法预检请求,后端需响应并设置CORS头来确认允许实际请求[^3]。 - CORS的实现完全由服务器驱动,开发者无需修改前端代码(前端AJAX调用与同源请求相同)[^3]。 #### 2. **后端实现CORS的关键步骤** 后端主要通过配置HTTP响应头来实现CORS。以下是通用的方法(适用于任何后端框架如Spring Boot、Node.js、Django等): **步骤1: 设置核心响应头** - **`Access-Control-Allow-Origin`**:指定允许访问的源。可以是具体名(如 `http://localhost:3000`)或通配符 `*`(允许所有源,但不安全)。 - 示例响应头:`Access-Control-Allow-Origin: http://localhost:3000` - 在代码中动态设置:根据请求的 `Origin` 头判断是否在允许列表中。 - **`Access-Control-Allow-Methods`**:指定允许的HTTP方法(如GET、POST、PUT)。 - 示例:`Access-Control-Allow-Methods: GET, POST, PUT` - **`Access-Control-Allow-Headers`**:指定允许的自定义请求头(如 `Authorization`)。 - 示例:`Access-Control-Allow-Headers: Content-Type, Authorization` - **`Access-Control-Allow-Credentials`**:如需传递cookies或认证信息,设为 `true`(但 `Access-Control-Allow-Origin` 不能为 `*`)。 - 示例:`Access-Control-Allow-Credentials: true` - 对于预检请求(OPTIONS方法),后端需返回这些头并设置状态码为204(No Content)。 **步骤2: 处理预检请求** - 后端需拦截OPTIONS请求,并在响应中添加上述头信息。 - 示例伪代码: ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值