Blogger Information
Blog 57
fans 3
comment 0
visits 59791
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
JS基础-跨域请求
岂几岂几
Original
728 people have browsed it

跨域请求

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标签的属性发起.

Correcting teacher:天蓬老师天蓬老师

Correction status:qualified

Teacher's comments:写得不错, 已经可以举一反三的
Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments
Author's latest blog post
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!