# 学习分享｜跨域解决、安卓开发探索、油猴脚本探索

原文：https://blog.grtsinry43.com/posts/learn-share-1/

作者：grtsinry43

发布时间：2024-06-09T21:22:48Z

内容更新时间：2024-06-09T21:22:48Z

最近学习的一些内容，包括跨域问题及其解决方案，安卓开发的简单探索，OpenAI的api做了个小插件

<!--more-->

额，把原来用Hexo托管在Github上的博客重新搞了一下，本来我是想坚持每天写博客的，但一直苦于没有时间~~（其实就是懒）~~，腾出时间把服务器和备案给搞了~~（又找借口）~~，本来想用Vue和Spring自己写的，但还没学完（ ）

## 一、跨域问题及其解决方案

### 1.概念

跨域问题是指在浏览器的同源策略下，不同域名、端口或协议之间的网页请求受到限制，导致某些跨域请求被浏览器阻止。同源策略是一种安全机制，防止恶意网站获取到用户的敏感信息。

**源：协议+域名+端口**

1. **不同域名**：比如从 `domain1.com` 发起请求到 `domain2.com`。
2. **不同端口**：比如从 `domain.com:3000` 发起请求到 `domain.com:4000`。
3. **不同协议**：比如从 `http://domain.com` 发起请求到 `https://domain.com`。

### 2.解决方案

1. **CORS（跨域资源共享）**：服务器端设置响应头，允许特定来源的请求。通过设置 `Access-Control-Allow-Origin` 头部来指定允许访问的域名，但是建议不要设置 `Access-Control-Allow-Origin: *`，在某些情况下只设置通配符会被理解为暂未配置。

比如使用nodejs处理一个简单的请求

```js
const express = require('express');
const app = express();
app.get('/', (req, res) => {
    res.header('Access-Control-Allow-Origin', '127.0.0.1');
    res.status(200).sendFile('XXX.html');
});
```

此时你能够在浏览器开发人员工具——网络选项卡看到这个响应头的一部分

这里注意，是只有在响应头中看到这段语句浏览器才能正常请求，找不到语句（没有默认是拒绝）或者没有请求所在的域名均不会成功

2. **JSONP（JSON with Padding）**：通过 `<script>` 标签的方式实现跨域请求。JSONP利用了 `<script>` 标签可以跨域加载的特性，不过只支持GET请求，并且存在安全性问题。

是早期的工程师们的非常天才的想法！这东西的原理是请求URL会返回类似`callbackFunction(data)`的字段，也就是一段js代码，这样可以使浏览器执行，从而实现预期效果

```html
<script src="https://otherdomain.com/data?callback=myFunction"></script>
function myFunction(data) {
  console.log(data);
}
```

3. **代理服务器**：在同源策略下，通过在同一个域名下创建API代理，让客户端请求自己的服务器，再由服务器转发请求到目标地址。这样可以绕过浏览器的限制。

```js
// 在服务器端发起请求
const resp = await axios.get('https://pvp.qq.com/web2 herolist.json');
// 将获取的数据返回给客户端
app.get('/', (req, res) => {
    res.header('Access-Control-Allow-Origin', '127.0.0.1');
    res.send(resp.data);
});
```

## 二、安卓开发的浅探索

这个其实是一个迫不得已的学习内容，起因是班级同学拽上我去参加一个嵌入式比赛，作品当然是大一专属的小车（蚌埠住了），他们希望亮点是软件，所以我就现学的安卓开发，本来还学了Kotlin一瘸一拐地写了点内容，但后来搞一些复杂的内容用一个不熟悉的语言还是太痛苦，所以还是回到了Java

 [GitHub](https://github.com/ "Github")

[grtsinry43/stm32-project-smartcontrol](https://github.com/grtsinry43/stm32-project-smartcontrol)

项目包括以下几个类：

- MainActivity.java：应用的主界面，实现手动控制，扫码反序列化，关于页面等功能
- BluetoothActivity.java：实现蓝牙的连接和通信
- ControlActivity.java：实现小车的控制指令的发送和接收
- QRCodeActivity.java：实现二维码的扫描和解析
- AboutActivity.java：显示应用的相关信息

所有都是现学的，我就大概说一下我学到了什么吧：

安卓开发是标准舒服的行为样式相分离，开发的单位是Java/Kotlin的类，每个界面是Activity，每个图形元素有对应的xml样式布局文件。大体上开发时候先用Adobe XD或者sigma（国内也可以即时设计啥的）设计好界面，然后为每个元素写xml文件，Activity里面通过id找到元素，可以添加、修改元素，可以监听元素动作（比如Button），但是通知线程服务啥的必须得学明白，别像我啥都不会，写的时候很痛苦

## 三、OpenAI的api简单使用

就是用js调用一个api，把回应显示出来，没什么复杂的，现在以我的技术只能做出这样（捂脸），前端有太多需要学的了......

```js
// ==UserScript==
// @name         GPT Answer
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Get GPT answer for selected text
// @author       You
// @match        *://*/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // 创建悬浮提示框
    var tooltip = document.createElement('div');
    tooltip.style.position = 'fixed';
    tooltip.style.zIndex = '9999';
    tooltip.style.display = 'none';
    tooltip.innerHTML = '<button id="gpt-answer">GPT回答</button>';

    // 创建GPT回答显示区域
    var answerArea = document.createElement('div');
    answerArea.style.position = 'fixed';
    answerArea.style.zIndex = '9999';
    answerArea.style.display = 'none';
    answerArea.style.outline = '1px solid';

    document.body.appendChild(tooltip);
    document.body.appendChild(answerArea);

    // 监听文本选择事件
    document.addEventListener('mouseup', function(e) {
        var selectedText = window.getSelection().toString().trim();
        if (selectedText) {
            var selectedElement = window.getSelection().anchorNode.parentNode;
            var rect = selectedElement.getBoundingClientRect();
            tooltip.style.left = (rect.right + 10) + 'px';
            tooltip.style.top = rect.top + 'px';
            tooltip.style.display = 'block';
        } else {
            tooltip.style.display = 'none';
        }
    });

    // 监听GPT回答按钮点击事件
    document.getElementById('gpt-answer').addEventListener('click', function() {
        var selectedText = window.getSelection().toString().trim();
        if (selectedText) {
            // 调用OpenAI API
            fetch('https://api.openai.com/v1/chat/completions', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': 'Bearer API_KEY'
                },
                body: JSON.stringify({
                    model: "gpt-3.5-turbo",
                    messages: [
                        {"role": "system", "content": "你是一个耐心回答问题的助手，请解答这个问题，谢谢！"},
                        {"role": "user", "content": selectedText}
                    ]
                })
            }).then(response => response.json())
            .then(data => {
                // 在固定位置显示GPT的回答
                var gptResponse = data['choices'][0]['message']['content'];
                answerArea.textContent = gptResponse;
                var selectedElement = window.getSelection().anchorNode.parentNode;
                var rect = selectedElement.getBoundingClientRect();
                answerArea.style.left = (rect.right + 10) + 'px';
                answerArea.style.top = (rect.bottom + 10) + 'px';
                answerArea.style.display = 'block';
            });
        }
    });

    // 监听页面点击事件，隐藏GPT回答显示区域
    document.addEventListener('click', function(e) {
        if (e.target !== answerArea && e.target !== tooltip && e.target !== document.getElementById('gpt-answer')) {
            answerArea.style.display = 'none';
        }
    });
})();
```
