博客列表 >JS基础-跨域请求

JS基础-跨域请求

岂几岂几
岂几岂几原创
2020年05月24日 16:58:01740浏览

跨域请求

1. CORS

  • CORS : 跨域资源共享

  • CSRF : 跨站请求伪造

    • 用户在访问A网站, 此时用户在A网站的信息记录在Cookie中, 假设A网站没有对Cookie做同源策略限制, 此时如果有B网站的链接嵌入到A网站中, 用户点开了该链接后, 跳转到B网站, 假设B网站是不怀好意的网站, 那么B网站的所有者就能获取到A网站的Cookie, 然后使用Cookie以该用户的身份去访问A网站.

    • 产生跨站伪造的原因就是网站没有遵循同源策略

1.2. 同源策略

  • 多个页面的协议, 域名, 端口完全相同, 则认为他们遵循了同源策略.

    • 协议: 要么是http, 要么是https等.

    • 域名: 多个页面的域名要完全相同. www.php.cnwww.php.net 是不同的!

    • 端口: 要么是80, 要么是443, 或者都是别的, 必须相同.

  • 同源策略是一种安全机制, 浏览器禁止通过脚本发起跨域请求, 如: XMLHttpRequest , Fetch API 等. 但是允许HTML标签属性跨域. 即, 可以用 <a> 标签或 <img> 发送跨域请求或跨域访问.

    • 当使用脚本发起跨域请求时, 浏览器会提示禁止跨域.

    • 此时, 若目标网站允许跨域, 则需要在跨域请求的目标请求头指定允许跨域访问自己的站点: header('Access-Control-Allow-Origin: http://php11.edu'). 记得一定要指定协议

      • 若不指定允许跨域访问的站点, 那么这个站点将是非常不安全的. 即, 不要这样设置: header('Access-Control-Allow-Origin: *')

1.3. JSONP跨域

  • 虽然同源策略不允许脚本发起跨域请求, 但是并不阻止HTML标签的属性发起. JSONP就是使用HTML标签的属性发起跨域请求的方式.
  1. <script src="把需要跨域的脚本URL写到这里发起一个跨域请求">
  2. </script>

实战案例

1. 通过HTML标签属性跨域

浏览器允许通过标签属性跨域

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>通过HTML标签属性跨域</title>
  7. </head>
  8. <body>
  9. <img src="https://img.php.cn/upload/image/234/213/408/1590257532837910.png" alt="球员列表" style="width: 400px;"><br>
  10. <a href="https://www.baidu.com">访问百度</a><br>
  11. <button type="button">发送跨域请求</button>
  12. </body>
  13. </html>

2. CORS跨域请求

php.edu站点的文件php.edu/0522/test1.php中设置允许站点php11.edu跨域

  1. <?php
  2. // 指定允许http://php11.edu站点跨域访问当前文件
  3. header('Access-Control-Allow-origin: http://php11.edu');
  4. echo '跨域请求返回的数据';
  5. // 刷新缓冲区
  6. flush();

php11.edu站点的php11.edu/js/0522/demo1.html使用ajax发起跨域访问请求

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>CORS跨域</title>
  7. </head>
  8. <body>
  9. <button type="button">发送跨域请求</button>
  10. <script>
  11. var btn = document.querySelector('button');
  12. btn.addEventListener('click', function() {
  13. // 通过ajax发送一个跨域请求
  14. var xhr = new XMLHttpRequest();
  15. xhr.onreadystatechange = function() {
  16. if(xhr.readyState === 4 && xhr.status === 200) {
  17. console.log(xhr.responseText);
  18. }
  19. }
  20. xhr.open('GET', 'http://php.edu/0522/test1.php', true);
  21. xhr.send(null);
  22. });
  23. </script>
  24. </body>
  25. </html>

成功获取到数据

3. JSONP跨域

php.edu站点中负责获取请求,并执行查询,调用回调函数.

  1. <?php
  2. // 这里返回json数据, 而json只支持utf8编码
  3. header('content-type: text/html;charset=utf-8');
  4. // 模拟根据id值获取数据, 并调用回调函数处理数据
  5. // 获取请求参数(jsonp指定一个回调函数名)
  6. $callback = $_GET['jsonp'];
  7. $id = $_GET['id'];
  8. // 返回的处理结果数组
  9. $res = [
  10. 'status' => '1',
  11. 'message' => '查询成功',
  12. ];
  13. // 判断id值是否有效
  14. if(!filter_var($id, FILTER_VALIDATE_INT, ['option' => ['min_range' => 1]])) {
  15. $res['status'] = '0';
  16. $res['message'] = 'ID值无效';
  17. }
  18. // 连接数据库
  19. $pdo = new PDO('mysql:host=localhost;dbname=phpedu;charset=utf8;port=3306', 'root', 'root');
  20. // 查询
  21. $stmt = $pdo->query("SELECT * FROM `player` WHERE `id` = {$id}");
  22. // 判断是否查到值
  23. if(!$stmt || $stmt->rowCount < 1) {
  24. // 没查到的处理
  25. $res['status'] = '0';
  26. $res['message'] = 'ID值无效';
  27. } else {
  28. // 查到数据
  29. $res['data'] = $stmt->fetch(PDO::FETCH_ASSOC);
  30. }
  31. // 打印回调
  32. echo $callback . '(' . json_encode(json_encode($res)) . ')';

php11.edu中通过JSONP发送跨域请求

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>通过JSONP跨域</title>
  7. </head>
  8. <body>
  9. <button>发送跨域请求</button>
  10. <script>
  11. /* 1. 被当做参数值传给跨域的目标站点, 目标站点echo "调用该函数的字符串",
  12. 相当于在当前站点执行该函数调用 */
  13. function handle(jsonData) {
  14. // console.log(jsonData);
  15. // json=>js对象
  16. var res = JSON.parse(jsonData);
  17. // 约定状态值为0表示查询结果异常
  18. if(res.status === '0') {
  19. alert(res.message ?? '查询失败');
  20. return;
  21. }
  22. // 渲染数据
  23. var ul = document.createElement('ul');
  24. ul.innerHTML += "<ul>姓名: " + res.data.name + "</ul>";
  25. ul.innerHTML += "<ul>球队: " + res.data.team + "</ul>";
  26. ul.innerHTML += "<ul>身高: " + res.data.height + "</ul>";
  27. ul.innerHTML += "<ul>体重: " + res.data.weight + "</ul>";
  28. ul.innerHTML += "<ul>位置: " + res.data.position + "</ul>";
  29. document.body.appendChild(ul);
  30. }
  31. </script>
  32. <script>
  33. /* 2. 给按钮增加点击事件, 生成一个跨域请求的script标签 */
  34. var btn = document.querySelector('button');
  35. btn.addEventListener('click', function () {
  36. // 生成一对<script>标签
  37. var script = document.createElement("script");
  38. // 为script标签的src属性赋予一个跨域请求的url, 并带上handle函数作为回调
  39. script.src = "http://php.edu/0522/test2.php?jsonp=handle&id=1";
  40. // 把生成的标签加到head标签中
  41. document.head.appendChild(script);
  42. // 相当于在head标签中生成了下面的标签, 然后就能自动发起跨域请求了
  43. // <-script src="http://php.edu/0522/test2.php?jsonp=handle&id=1"><-/script>
  44. }, false);
  45. </script>
  46. </body>
  47. </html>

执行结果:

  • 查询到值时

  • 查询不到值

学习心得

跨域访问涉及到网站安全, 必须要注意. 成功跨域访问, 一种是访问的目标站点指定了当前站点允许跨域访问(CORS); 另一种是曲线救国, 使用HTML标签的属性发起.

声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议