每周总结1/8(spring跨域问题与百度接口node.js跨域问题解决)

发布时间 2024-01-08 20:21:35作者: 橘子味芬达水
//baidu.js文件,接收传递的图片,进行base64处理,上传百度接口返还json处理结果
const express = require('express'); const multer = require('multer'); const request = require('request'); const cors = require('cors'); // 添加cors模块 const app = express(); const upload = multer(); const AK = 'DGlSAAl75rCpOw73dREwYGCX'; const SK = '21GKHyFB5QmEZ6MOOxwKWCh8ngUjSr9U'; app.use(cors()); // 使用cors中间件 app.post('/process-image', upload.single('image'), async (req, res) => { const imageBase64 = req.file.buffer.toString('base64'); const accessToken = await getAccessToken(); const options = { method: 'POST', url: `https://aip.baidubce.com/rest/2.0/ocr/v1/multiple_invoice?access_token=${accessToken}`, headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json' }, form: { image: imageBase64, verify_parameter: 'true', probability: 'false', location: 'false' } }; request(options, (error, response, body) => { if (error) { console.error(error); res.status(500).json({ error: 'An error occurred' }); } else { res.json({ body }); } }); }); function getAccessToken() { const options = { method: 'POST', url: `https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=${AK}&client_secret=${SK}` }; return new Promise((resolve, reject) => { request(options, (error, response, body) => { if (error) { reject(error); } else { resolve(JSON.parse(body).access_token); } }); }); } app.listen(8082, () => { console.log('Server is running on port 8082'); });

前端代码

<template>
    <div>
        <div class="nav">
            <el-breadcrumb separator="/">
                <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
                <el-breadcrumb-item><a href="/">主菜单</a></el-breadcrumb-item>
                <el-breadcrumb-item>支出管理</el-breadcrumb-item>
                <el-breadcrumb-item>报销汇总</el-breadcrumb-item>
            </el-breadcrumb>
        </div>
        <div>
            <el-table :data="poi" style="width: 100%">
                <el-table-column prop="id" label="发票编号" width="100"></el-table-column>
                <el-table-column prop="pdata" label="开票日期" width="100"></el-table-column>
                <el-table-column prop="pchaser" label="开票人员" width="100"></el-table-column>

                <el-table-column prop="itname" label="物品名称" width="100"></el-table-column>
                <el-table-column prop="pnum" label="商品数量" width="100"></el-table-column>
                <el-table-column prop="unit" label="单位" width="100"></el-table-column>
                <el-table-column prop="aprice" label="单价" width="100"></el-table-column>
                <el-table-column prop="pmoney" label="实际金额" width="100"></el-table-column>
                <el-table-column prop="qi" label="其他花费" width="100"></el-table-column>
                <el-table-column prop="piao" label="发票图片" width="100"></el-table-column>
                <el-table-column prop="pstatus" label="当前状态" width="100"></el-table-column>
                <el-table-column label="操作" width="200">
                    <template slot-scope="scope">
                        <div class="button-group">
                            <el-button
                                v-if="scope.row.pstatus === '已批准'"
                                type="success"
                                icon="el-icon-check"
                                size="mini"
                                @click="pass(scope.row)"
                            >
                                报销
                            </el-button>
                            <el-button
                                type="primary"
                                icon="el-icon-edit"
                                size="mini"
                                @click="edit(scope.row)"
                            >
                                编辑
                            </el-button>
                        </div>
                    </template>
                </el-table-column>
            </el-table>
            <el-dialog :visible.sync="dialogVisible" title="编辑数据" width="100%">
                <el-form :model="editForm" status-icon :rules="rules" ref="editForm" label-width="100px" class="demo-ruleForm">
                    <!-- ... other form items ... -->
                    <el-form-item label="其他花费" prop="qi">
                        <el-input v-model="editForm.qi"></el-input>
                    </el-form-item>
                    <el-form-item label="实际金额" prop="pmoney">
                        <el-input v-model="editForm.pmoney"></el-input>
                    </el-form-item>
                    <el-form-item label="发票图片" prop="unit">
                        <img :src="image" v-if="image" alt="发票预览图"/>
                        <el-input v-model="editForm.piao"></el-input>
                    </el-form-item>

                    <template>
                        <div>
                            <input type="file" @change="handleFileChange" />
                            <button @click="submitImage">提交</button>
                            <el-form-item label="识别结果">
                                <div v-if="result">
                                    <div class="invoice-info">
                                        <div>发票金额: {{ this.result.words_result[0].result.total_amount[0].word }}</div>
                                        <div>发票编号: {{ this.result.words_result[0].result.invoice_num[0].word }}</div>
                                        <div>发票类型: {{ this.result.words_result[0].result.invoice_type[0].word }}</div>
                                        <div>发票日期: {{ this.result.words_result[0].result.invoice_date[0].word }}</div>
                                    </div>
                                </div>
                            </el-form-item>
                        </div>
                    </template>

                    <el-form-item>
                        <el-button type="primary" @click="submitEditForm">提交</el-button>
                        <el-button @click="resetForm('editForm')">重置</el-button>
                    </el-form-item>
                </el-form>
            </el-dialog>

        </div>

    </div>
</template>

<script>

import axios from "axios";
export default {
    name: "paytotal",
    data() {
        return {
            poi: {},
            editRow: null,
            dialogVisible: false,
            editForm: {
                id: "",
                qi: "",
                piao: "",
                pmoney: null,
                pdata: "",
                pchaser: "",
                itname: "",
                pnum: "",
                unit: "",
                aprice: null,
                pstatus: "",
                pda: "",
                result: {},
                results: '',
                results1: '',
                file: null,
                image: null // 添加image属性

            },
        };

    },
    created() {
        // 在组件创建时,发送请求获取后端数据
        this.fetchBooks();
    },

    methods: {
        fetchBooks() {
            // 使用axios发送GET请求到后端数据接口
            axios.get("http://localhost:8088/poi/getAll").then(response => {
                // 将返回的数据赋值给books属性
                this.poi = response;
                console.log(this.poi)
            });
        },
        edit(row) {
            // 将选中行的数据赋值给editForm
            this.editForm = { ...row };
            // 打开编辑对话框
            this.dialogVisible = true;
        },
        handleFileChange(event) {
            this.file = event.target.files[0];
            this.image = URL.createObjectURL(this.file); // 将图像文件转换为URL对象
        },

        async submitImage() {
            const formData = new FormData();
            formData.append('image', this.file);
            try {
                const response = await fetch('http://localhost:8082/process-image', {
                    method: 'POST',
                    body: formData,
                });
                const data = await response.json();
                // 解析嵌套的JSON字符串
                this.result = JSON.parse(data.body);

                // 假设OCR服务返回了图片URL(或处理后的任何其他相关数据)
                this.editForm.piao = this.result.image_url;  // 根据实际情况调整

                // ... 其他逻辑 ...
            } catch (error) {
                console.error(error);
            }
        },
        pass(row) {
            axios
                .put("http://localhost:8088/yuan/update1", { ename: row.pchaser, pmoney: row.pmoney ,qi:row.qi})
                .then(response => {
                    console.log(response);
                    this.fetchBooks();
                })
                .catch(error => {
                    console.error(error);
                });
            axios
                .put("http://localhost:8088/poi/update", { id:row.id, pstatus: "已报销" })
                .then(response => {
                    console.log(response);
                    this.fetchBooks();
                })
                .catch(error => {
                    console.error(error);
                });
        },
        submitEditForm() {
            this.$refs.editForm.validate(valid => {
                if (valid) {
                    axios
                        .put("http://localhost:8088/poi/update1", this.editForm)
                        .then(response => {
                            console.log(response);
                            this.dialogVisible = false;
                            this.fetchBooks();
                        })
                        .catch(error => {
                            console.error(error);
                        });
                } else {
                    console.log("error submit!!");
                    return false;
                }
            });
        },
        resetForm(formName) {
            this.$refs[formName].resetFields();
        },
    }
};
</script>

<style>
.el-input {
    margin-bottom: 15px;
}
.nav {
    margin-bottom: 15px;
    font-size: 32px;
}
.upload-demo {
    display: inline-block;
    margin-right: 5px;
}
.invoice-info {
    margin-top: 10px; /* Adjust the margin based on your design */
    padding-left: 100px; /* Match the label-width of other form items */
}
</style>

使用前记得运行js文件,node baidu.js

这段代码是一个基于Node.js和Express框架搭建的后端服务,用于处理图像识别相关的API请求。其中涉及跨域问题的部分是通过引入并使用了cors模块来解决的。

具体解决步骤如下:

  1. 首先,通过const cors = require('cors')引入了cors模块,这是一个Express中间件,用于提供跨域资源共享(CORS)的功能。

  2. 紧接着,在应用实例化之后,使用了 app.use(cors()) 这一行代码,它表明在所有路由之前添加了cors中间件。这一步至关重要,因为当浏览器发起跨域请求时,服务器需要明确允许该来源(origin),才能成功响应跨域请求。

  3. cors()函数默认配置为允许任何源(origin)发起的跨域请求,这对于开发环境通常足够宽松,但在生产环境中可能需要更严格的控制,例如指定特定的域名或设置特定的请求头等。

通过上述步骤,当前端应用从不同的源(domain或协议)向该后端服务的 /process-image API 发起POST请求时,由于已经启用了cors中间件,所以即使前后端不在同一个域下,也能顺利完成数据交互,从而解决了跨域问题。

spring解决跨域问题

package com.itheima.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class corsConfig {
    @Bean
    public CorsFilter corsFilter(){
        UrlBasedCorsConfigurationSource source=new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration=new CorsConfiguration();
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.addAllowedOrigin("*");
        source.registerCorsConfiguration("/**",corsConfiguration);
        return new CorsFilter(source);
    }
}

这段Java代码是基于Spring框架实现的跨域资源共享(CORS)配置,它定义了一个处理跨域请求的过滤器(CorsFilter),允许来自任何源(origin)、任何头信息(header)和任何HTTP方法(method)的请求。

代码解释:

  1. @Configuration 注解表明这个类是一个配置类,其中包含了一系列可被Spring IoC容器管理的Bean定义。

  2. @Bean 注解的方法会返回一个对象实例,并注册到Spring容器中。在这个例子中,corsFilter() 方法创建并返回了一个 CorsFilter 实例。

  3. CorsConfiguration 类是用来配置CORS策略的,它允许你指定哪些域名、HTTP方法以及自定义头部可以被浏览器跨域访问:

    • corsConfiguration.addAllowedHeader("*"); 表示允许所有的请求头。
    • corsConfiguration.addAllowedMethod("*"); 表示允许所有的HTTP方法,如GET、POST等。
    • corsConfiguration.addAllowedOrigin("*"); 设置允许所有来源(即任何域名或IP地址)发起的跨域请求。
  4. UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); 创建了一个基于URL的CORS配置源对象。

  5. source.registerCorsConfiguration("/**", corsConfiguration); 这行代码将之前配置好的CORS规则注册到全局路径 "/**" 上,这意味着该配置将应用于所有路由。

  6. 最后,通过 new CorsFilter(source) 创建了一个 CorsFilter 对象,并将其注入到Spring容器作为Bean。当应用接收到客户端(通常是Web浏览器)发起的跨域请求时,这个过滤器就会启用已配置的CORS策略,从而解决跨域问题,使得服务器端能够响应来自不同源的请求。

总结来说,此配置允许任何源的前端应用向后端发送跨域请求,且不限制请求方法与请求头,这是一种较为宽松的跨域设置,适用于开发阶段或特定的应用场景。在实际生产环境中,可能需要根据实际情况细化CORS策略,仅允许特定的域名、方法和头部进行跨域访问以确保安全性。