Java Spring Boot中RestTemplate提交Google表单遇400错误求助
问题描述
新用户注册时需提交一份Google表单,我用Java Spring Boot的RestTemplate发送请求,将表单数据通过查询参数传递。纯文本参数能正常提交,但下拉选择项会触发400错误。奇怪的是,从RestTemplate调用中复制生成的URL,在浏览器或Postman里提交完全正常,求帮忙排查代码和URL的问题。
相关代码
private static final String GOOGLE_FORM_URL_V2 = "https://docs.google.com/forms/d/e/1FAIpQLSeb_QX8rdKD2WOM5-0rZ10C9rzPsMzqlGL-Aduh7_nM0EEutw/formResponse"; public Boolean submitGoogleFormV2(UserDto userDto) { String sampleWhatsappMessage = "Hi David! Your Order is booked and it will be delivered in two days. Thanks for trusting us."; String country = new Locale("en", PhoneNumberUtil.getInstance().getRegionCodeForCountryCode(userDto.getCountryCode())).getDisplayCountry(); UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(GOOGLE_FORM_URL_V2) .queryParam("submit", "Submit") .queryParam("entry.294840288", "Both of the above") // What type of messages will you be sending with WhatsApp? .queryParam("entry.305369145", userDto.getPhoneNumber()) // phone number .queryParam("entry.365096862", vonageApiProperties.getMasterKey()) // Vonage API Key // TODO: Generate new api key for this whatsapp number .queryParam("entry.400495561", "tbc") // Vonage API key for WhatsApp Traffic .queryParam("entry.631769330", userDto.getRegion().getText()) // Your Region .queryParam("entry.901955710", userDto.getFirstName() + " " + userDto.getLastName()) // Your Name .queryParam("entry.1208336345", "up to 10,000 Messages / month") // Estimated monthly messages volume .queryParam("entry.1259584144", userDto.getEmail()) // Your Email Address .queryParam("entry.1489275520", userDto.getBrandName()) // Brand Name .queryParam("entry.1510504567", country + " " + userDto.getCountryCode().toString()) // Phone number's country code .queryParam("entry.1595895866", userDto.getCompanyName()) // Company Name .queryParam("entry.1602423798", userDto.getEmail()) // Email address(s) to be added to the WhatsApp Manager .queryParam("entry.1731935104", "No") // Is your chosen WhatsApp phone number a Vonage long virtual number (LVN)? .queryParam("entry.1807529240", "Not sure") // Estimated peak messages per second: indicate daily, weekly, or monthly. .queryParam("entry.2012164249", "Other/ Don't know") // What is your business vertical? .queryParam("entry.292494179", "") // Partner Name .queryParam("entry.565847730", "") // Other Email Addresses to be CC'd .queryParam("entry.1792374253", "") // Vonage Account Manager's email address .queryParam("entry.166684008", userDto.getFbBusinessManagerId()) // Company Facebook Business Manager ID .queryParam("entry.1328375169", "") // Company Facebook URL .queryParam("entry.1366161341", "") // Company website .queryParam("entry.1461623644", sampleWhatsappMessage) // Please provide example message(s) you would be sending over WhatsApp .queryParam("entry.309718730", "1000") // What is your expected monthly spend on this project? .queryParam("entry.1279938927", ""); // Any Additional Notes HttpHeaders headers = new HttpHeaders(); headers.set("Accept", "*/*"); headers.set("User-Agent", "Mozilla/5.0"); HttpEntity<?> entity = new HttpEntity<>(headers); try { ResponseEntity<String> response = restTemplate.postForEntity(builder.toUriString(), entity, String.class); log.info("Successfully sent google from to Vonage. Response: {}", response.getBody()); return true; } catch (Exception e) { log.error("Unable to send google form to vonage. Error: {}", e.getMessage()); return false; } }
生成的请求URL
https://docs.google.com/forms/d/e/1FAIpQLSeb_QX8rdKD2WOM5-0rZ10C9rzPsMzqlGL-Aduh7_nM0EEutw/formResponse?submit=Submit&entry.294840288=Both%20of%20the%20above&entry.305369145=3326252240&entry.365096862=38f794d8&entry.400495561=tbc&entry.631769330=South%20East%20Asia%20(SEA)&entry.901955710=Umaid%20Ashraf&entry.1208336345=up%20to%2010,000%20Messages%20/%20month&entry.1259584144=umaidashraf0@gmail.com&entry.1489275520=Devestem&entry.1510504567=Pakistan%2092&entry.1595895866=Devestem&entry.1602423798=umaidashraf@gmail.com&entry.1731935104=No&entry.1807529240=Not%20sure&entry.2012164249=Other/%20Don't%20know&entry.292494179=&entry.565847730=&entry.1792374253=&entry.166684008=121026849979786&entry.1328375169=&entry.1366161341=&entry.1461623644=Hi%20David!%20Your%20Order%20is%20booked%20and%20it%20will%20be%20delivered%20in%20two%20days.%20Thanks%20for%20trusting%20us.&entry.309718730=1000&entry.1279938927=
排查与解决方案
问题根源在于请求方式和参数传递逻辑不匹配,以及编码细节差异:
请求方式不符合预期:Google表单默认期望
POST请求将数据放在请求体(x-www-form-urlencoded格式),而非URL查询参数。浏览器/Postman能兼容URL参数的提交方式,但RestTemplate发送空请求体+URL参数的POST请求时,服务器对下拉选项这类有固定值限制的字段校验更严格,从而触发400错误。编码规则差异:
UriComponentsBuilder的字符编码规则和浏览器存在细微差别,比如单引号'、斜杠/的处理,下拉选项文本对编码准确性要求更高,一旦编码不一致就会导致服务器识别失败。
修复步骤:
- 改用表单提交格式:将参数放在请求体中,以
x-www-form-urlencoded格式发送,不再拼在URL里。调整后的代码如下:
public Boolean submitGoogleFormV2(UserDto userDto) { String sampleWhatsappMessage = "Hi David! Your Order is booked and it will be delivered in two days. Thanks for trusting us."; String country = new Locale("en", PhoneNumberUtil.getInstance().getRegionCodeForCountryCode(userDto.getCountryCode())).getDisplayCountry(); // 构建表单参数 MultiValueMap<String, String> formParams = new LinkedMultiValueMap<>(); formParams.add("submit", "Submit"); formParams.add("entry.294840288", "Both of the above"); formParams.add("entry.305369145", userDto.getPhoneNumber()); formParams.add("entry.365096862", vonageApiProperties.getMasterKey()); formParams.add("entry.400495561", "tbc"); formParams.add("entry.631769330", userDto.getRegion().getText()); formParams.add("entry.901955710", userDto.getFirstName() + " " + userDto.getLastName()); formParams.add("entry.1208336345", "up to 10,000 Messages / month"); formParams.add("entry.1259584144", userDto.getEmail()); formParams.add("entry.1489275520", userDto.getBrandName()); formParams.add("entry.1510504567", country + " " + userDto.getCountryCode().toString()); formParams.add("entry.1595895866", userDto.getCompanyName()); formParams.add("entry.1602423798", userDto.getEmail()); formParams.add("entry.1731935104", "No"); formParams.add("entry.1807529240", "Not sure"); formParams.add("entry.2012164249", "Other/ Don't know"); formParams.add("entry.292494179", ""); formParams.add("entry.565847730", ""); formParams.add("entry.1792374253", ""); formParams.add("entry.166684008", userDto.getFbBusinessManagerId()); formParams.add("entry.1328375169", ""); formParams.add("entry.1366161341", ""); formParams.add("entry.1461623644", sampleWhatsappMessage); formParams.add("entry.309718730", "1000"); formParams.add("entry.1279938927", ""); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); headers.set("User-Agent", "Mozilla/5.0"); HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(formParams, headers); try { ResponseEntity<String> response = restTemplate.postForEntity(GOOGLE_FORM_URL_V2, entity, String.class); log.info("Successfully sent google form to Vonage. Response: {}", response.getBody()); return true; } catch (Exception e) { log.error("Unable to send google form to vonage. Error: {}", e.getMessage()); return false; } }
- 验证下拉选项文本:确保传递的下拉选项文本和Google表单后台的选项完全一致,包括空格、标点符号,比如
"Other/ Don't know"要和表单内的选项完全匹配,避免因文本不一致触发400错误。
内容的提问来源于stack exchange,提问作者umaid ashraf
相关产品推荐
相关产品推荐

