问题描述
关于项目
我上手Java不久,对网络编程不太熟悉,于是做了一个网络同步剪切板的小程序,思路是这样的:在服务端开一个api url,对这个URL使用POST,上传JSON数据以对剪切板做操作,比如如果想要写数据就定义如下的JSON数据:
{
"action": "write",
"contents": "Something you wanna upload."
}
就是这样一个简单的小程序,应该能够扩展成历史剪切板之类的功能,不过感觉这样发展下去就是Pocket或者Flomo了,所以还是应该使其保持简单。
遇到的问题
我使用Emacs的request库调试的时候工作正常,Debug的时候能够显示我做了哪些操作,System.out输出如下:
Method: POST
Write from client!
{"code":200,"content":"为啥啊䓍","message":"Success!"}
Method: POST
Read from client!
{"code":200,"content":"为啥啊䓍","message":"Success!"}
Method: POST
Write from client!
{"code":200,"content":"为啥啊䓍","message":"Success!"}
但是如果是从iPad上面,使用捷径里面那个“获取URL内容”用POST方法上传JSON的话却不能完成功能。
更加离奇的是昨天试的时候我在局域网试验发现可以用iPad上传只是服务器不能够上传,但是今天却发现连局域网里面也上传不了了,如上面的Debug记录可见,上面的行为都是我使用Emacs的request发出的,iPad捷径里面做的操作好像根本没有被程序察觉到。
我做的尝试
是Cache的问题吗?
我试了请求的时候要求 no-cache 也还是没有作用,而且每次我上传的东西是不同的,也会触发缓存机制吗?因此我觉得这个可能性不大。
是因为POST的实现问题吗?
POST可以用GET实现,将表单里面的东西放到URL里面,也许就会让我的JSON处理程序无东西可以处理,但是这样说不通,因为我调试的时候定义了doGet方法为返回一个提示用户"Please do POST"的一级标题。
这是我用netcat调试的时候收到的iPad数据:
POST /netcat/ HTTP/1.0
Host: localhost:1453
X-Real-IP: 172.20.10.1
X-Forwarded-For: 172.20.10.1
Connection: close
Content-Length: 37
Content-Type: application/json
User-Agent: BackgroundShortcutRunner/1144.4 CFNetwork/1325.0.1 Darwin/21.1.0
Accept: */*
Accept-Language: zh-CN,zh-Hans;q=0.9
Accept-Encoding: gzip, deflate
Cache-Control: no-cache
{"action":"write","contents":"Hello"}
附上我的nginx的配置
server {
listen 80;
server_name 172.20.10.5;
root /var/www/public;
location /netcat/ {
proxy_pass http://localhost:1453;
proxy_set_header Host $proxy_host; # 修改转发请求头,让8080端口的应用可以受到真实的请求
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
netcat 监听命令
nc -l localhost 1453
wsug
2022 年1 月 4 日 15:38
3
我似乎也遇到过类似问题,用elisp的(url-retrieve)
发起的post请求,数据是json形式的,服务器端是php的取不到post数据,即php的全局变量$_POST没有值。
最后解决办法是:服务器端直接读取http请求头的原始数据流,即json数据,将其转换为需要的数据格式(如数组)在处理。
我解决的代码是:$_POST=json_decode( file_get_contents("php://input"),1);
, java没有折腾过网络编程不知道如何读取http原始请求头
好的,项目在这里
新手项目,可能有些地方会有点匪夷所思。
主要的逻辑
package cn.colawithsauce;
import ActionHandler.*;
import ActionHandler.WriteActionHandler;
import com.alibaba.fastjson.JSONObject;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
@WebServlet(urlPatterns = "/")
public class clipboardServer extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
This file has been truncated. show original
思路是根据用户的要求来初始化不同的类,然后再对此类进行执行操作来将内容输出给用户
ActionHandler 接口类
WriteActionHandler implements ActionHandler
代码逻辑应该不算太复杂,上面列出的都是我觉得跟这个问题有关的代码。
意思是硬编码到URL里面并改用GET吗?其实也是一个思路,就是觉得这样不太优雅所以一直不肯去搞,明天试试
wsug
2022 年1 月 5 日 10:47
9
不是,我就是先判断http请求头的数据流是不是json字符串,如果是就用json_decode()转换成数组,然后数组命名成了$_POST,这个命名可能会造成误解,也许应该换一个。
意思是把json字符串硬编码到url里面吗?这样也不错。
kent
2022 年1 月 6 日 03:58
10
server 的代码看起来没问题。再确认一下你的快捷指令用的没问题吧,可以给https://httpbin.org/post 发送一个请求验证一下,这个接口会把你的请求信息返回来,类似这样
和用Emacs的request发送的请求头的区别只有UserAgent不同,但是如果手动在捷径里面指定UserAgent为curl,也不能解决问题。
解决了,居然是URL的问题,将URL从 https://path/to/url/api/clipboard
在最后加一个斜杠就好了 https://path/to/url/api/clipboard/
就能够正常发送了。
但是为什么?我更加疑惑了,这两个有什么不同吗?
kent
2022 年1 月 6 日 04:36
14
2 个赞
谢谢,学习到了!谷歌了一下才知道原来加了 trailing-slash 会有不同的
wsug
2022 年1 月 8 日 01:18
16
这问题我也遇到过,有时候要加/,有时候又不能加,还有些api,通过url get方法传参数,在生成参数时字符串最后多了一个分割符&,get参数就不能被解析了,而一般多数网站会忽略掉get参数最后的&,或url最后的/。
理由有很多,但我感觉可能就是程序员偷赖而已,在服务端忘记了多写几行代码判断一下
我们这暗夜模式的特殊格式文字的字体背景颜色不行啊。。。