每周总结1/8(spring跨域问题与百度接口node.js跨域问题解决)
//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模块来解决的。
具体解决步骤如下:
-
首先,通过
const cors = require('cors')
引入了cors模块,这是一个Express中间件,用于提供跨域资源共享(CORS)的功能。 -
紧接着,在应用实例化之后,使用了
app.use(cors())
这一行代码,它表明在所有路由之前添加了cors中间件。这一步至关重要,因为当浏览器发起跨域请求时,服务器需要明确允许该来源(origin),才能成功响应跨域请求。 -
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)的请求。
代码解释:
-
@Configuration
注解表明这个类是一个配置类,其中包含了一系列可被Spring IoC容器管理的Bean定义。 -
@Bean
注解的方法会返回一个对象实例,并注册到Spring容器中。在这个例子中,corsFilter()
方法创建并返回了一个CorsFilter
实例。 -
CorsConfiguration
类是用来配置CORS策略的,它允许你指定哪些域名、HTTP方法以及自定义头部可以被浏览器跨域访问:corsConfiguration.addAllowedHeader("*");
表示允许所有的请求头。corsConfiguration.addAllowedMethod("*");
表示允许所有的HTTP方法,如GET、POST等。corsConfiguration.addAllowedOrigin("*");
设置允许所有来源(即任何域名或IP地址)发起的跨域请求。
-
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
创建了一个基于URL的CORS配置源对象。 -
source.registerCorsConfiguration("/**", corsConfiguration);
这行代码将之前配置好的CORS规则注册到全局路径"/**"
上,这意味着该配置将应用于所有路由。 -
最后,通过
new CorsFilter(source)
创建了一个CorsFilter
对象,并将其注入到Spring容器作为Bean。当应用接收到客户端(通常是Web浏览器)发起的跨域请求时,这个过滤器就会启用已配置的CORS策略,从而解决跨域问题,使得服务器端能够响应来自不同源的请求。
总结来说,此配置允许任何源的前端应用向后端发送跨域请求,且不限制请求方法与请求头,这是一种较为宽松的跨域设置,适用于开发阶段或特定的应用场景。在实际生产环境中,可能需要根据实际情况细化CORS策略,仅允许特定的域名、方法和头部进行跨域访问以确保安全性。