13、深入理解HTTP请求:POST、PUT、DELETE及各类Web服务请求

深入理解HTTP请求:POST、PUT、DELETE及各类Web服务请求

1. HTTP POST请求

在进行HTTP POST请求时,不能像GET请求那样使用URL类的 getText() 快捷方式。必须获取 URLConnection 对象,将请求方法设置为POST(GET是默认方法)。对于GET请求,查询字符串会附加在URL对象的末尾;而POST请求的查询字符串则嵌入在请求体中。要实现这一点,需要完成以下三个步骤:
1. 将 URLConnection 的 doOutput 值设置为 true 。
2. 获取 outputStream 。
3. 在调用 connect() 之前,将查询字符串写入 outputStream 。

以下是一个简单的HTTP POST请求示例:

def url = new URL("http://search.yahoo.com/search")
def connection = url.openConnection()
//switch the method to POST (GET is the default)
connection.setRequestMethod("POST")
//write the data
def queryString = "n=20&vf=pdf&p=groovy+grails"
connection.doOutput = true
Writer writer = new OutputStreamWriter(connection.outputStream)
writer.write(queryString)
writer.flush()
writer.close()
connection.connect()
//print the results
println connection.content.text
从列表构建查询字符串

从列表构建查询字符串的关键是确保值进行URL编码,然后用 & 将元素连接起来。示例代码如下:

def queryString = []
queryString << "n=" + URLEncoder.encode("20")
queryString << "vf=" + URLEncoder.encode("pdf")
queryString << "p=" + URLEncoder.encode("groovy grails")
def url = new URL("http://search.yahoo.com/search")
def connection = url.openConnection()
connection.setRequestMethod("POST")
connection.doOutput = true
Writer writer = new OutputStreamWriter(connection.outputStream)
writer.write(queryString.join("&"))
writer.flush()
writer.close()
connection.connect()
def results = conn.content.text
创建便利的Post类

将复杂的连接逻辑封装到 Post 类中,结合之前创建的 QueryString 类,可以提供更好的开发体验。示例代码如下:

class Post{
    String url
    QueryString queryString = new QueryString()
    URLConnection connection
    String text
    String getText(){
        def thisUrl = new URL(url)
        connection = thisUrl.openConnection()
        connection.setRequestMethod("POST")
        connection.doOutput = true
        Writer writer = new OutputStreamWriter(connection.outputStream)
        writer.write(queryString.toString())
        writer.flush()
        writer.close()
        connection.connect()
        return connection.content.text
    }
    String toString(){
        return "POST:\n" +
                url + "\n" +
                queryString.toString()
    }
}
def post = new Post(url:"http://search.yahoo.com/search")
post.queryString.add("n", 20)
post.queryString.add("vf", "pdf")
post.queryString.add("p", "groovy grails")
println post
println post.text
模拟HTML表单进行测试

有了 Post 类后,可以使用代码轻松模拟HTML表单提交。以下是一个示例:

<form method="post" action="http://localhost:8888/jaw/controller">
    <input type="hidden" name="action" value="saveCar" />
    Make:
    <input type="text" name="make" value="" /></td>
    Model: <input type="text" name="model" value="" /></td>
    Year:
    <input type="text" name="modelYear" value="" /></td>
    <input type="submit" name="save" value="Save" />
</form>

对应的模拟代码如下:

def post = new Post(url:"http://localhost:8888/jaw/controller")
post.queryString.add("action", "saveCar")
post.queryString.add("make", "Toyota")
post.queryString.add("model", "Prius")
post.queryString.add("modelYear", 2012)
println post.text
RESTful POST请求使用XML

在RESTful Web服务中,HTTP动词具有深刻的语义含义。通常,RESTful服务期望POST请求的主体是XML,而不是之前演示的查询字符串。要传递XML,需要对代码进行两个小的更改:
1. 将 Content-Type 从 application/x-www-form-urlencoded (POST的默认值)更改为 application/xml (具体的 Content-Type 取决于所调用的RESTful服务)。
2. 不对数据进行URL编码,XML有效负载应按其原始格式传输。

示例代码如下:

def xml = """<car>
    <make>Toyota</make>
    <model-year>2012</model-year>
    <model>Prius</model>
</car>"""
def url = new URL("http://localhost:8888/jaw/car")
def connection = url.openConnection()
//set the metadata
connection.setRequestMethod("POST")
connection.setRequestProperty("Content-Type","application/xml")
//write the data
connection.doOutput = true
Writer writer = new OutputStreamWriter(connection.outputStream)
writer.write(xml)
writer.flush()
writer.close()
connection.connect()
def results = connection.content.text
2. HTTP PUT请求

执行HTTP PUT请求在语法上与POST请求相同,唯一的区别是将请求方法设置为 PUT 。PUT在语义上相当于数据库的UPDATE操作。示例代码如下:

def xml = """<car id="142">
    <make>Toyota</make>
    <model-year>2012</model-year>
    <model>Prius, Luxury Edition</model>
</car>"""
def url = new URL("http://localhost:8888/jaw/car/142")
def connection = url.openConnection()
connection.setRequestMethod("PUT")
connection.setRequestProperty("Content-Type","application/xml")
connection.doOutput = true
Writer writer = new OutputStreamWriter(connection.outputStream)
writer.write(xml)
writer.flush()
writer.close()
connection.connect()
def result = connection.content.text
创建便利的Put类

Put 类与 Post 类几乎相同,但有三个区别:
1. queryString 字段替换为普通的 String body 字段。
2. 暴露 contentType 字段,以便根据需要进行更改。
3. 请求方法设置为 PUT 。

示例代码如下:

class Put{
    String url
    String body
    String contentType = "application/xml"
    URLConnection connection
    String text
    String getText(){
        def thisUrl = new URL(url)
        connection = thisUrl.openConnection()
        connection.setRequestMethod("PUT")
        connection.setRequestProperty("Content-Type", contentType)
        connection.doOutput = true
        Writer writer = new OutputStreamWriter(connection.outputStream)
        writer.write(body)
        writer.flush()
        writer.close()
        connection.connect()
        return connection.content.text
    }
    String toString(){
        return "PUT:\n" +
                contentType + "\n" +
                url + "\n" +
                body
    }
}
def xml = """<car id="142">
    <make>Toyota</make>
    <model-year>2012</model-year>
    <model>Prius, Luxury Edition</model>
</car>"""
def put = new Put(url:"http://localhost:8888/jaw/car/142")
put.body = xml
println put
def result = put.text
3. HTTP DELETE请求

执行HTTP DELETE请求在语法上与GET请求相同,唯一的区别是将请求方法设置为 DELETE 。与POST和PUT请求不同,GET和DELETE请求(以及HEAD、OPTION等其他HTTP动词)只包含URL。示例代码如下:

def url = new URL("http://localhost:8888/jaw/car/142")
def connection = url.openConnection()
connection.setRequestMethod("DELETE")
connection.connect()
def result = connection.content.text
创建便利的Delete类

Delete 类与 Get 类几乎相同,唯一的区别是请求方法设置为 DELETE 。示例代码如下:

class Delete{
    String url
    QueryString queryString = new QueryString()
    URLConnection connection
    String text
    String getText(){
        def thisUrl = new URL(this.toString())
        connection = thisUrl.openConnection()
        connection.setRequestMethod("DELETE")
        if(connection.responseCode == 200){
            return connection.content.text
        }
        else{
            return "Something bad happened\n" +
                    "URL: " + this.toString() + "\n" +
                    connection.responseCode + ": " +
                    connection.responseMessage
        }
    }
    String toString(){
        return "DELETE:\n" +
                url + "?" + queryString.toString()
    }
}
def delete = new Delete(url:"http://localhost:8888/jaw/car/142")
println delete
def results = delete.text
4. RESTful请求

可以使用RESTful请求获取地址的经纬度信息。示例代码如下:

def partialRestRequest = "http://geocoder.us/service/rest/geocode?address="
def address = "1600 Pennsylvania Ave, Washington DC"
def restUrl = new URL(partialRestRequest + URLEncoder.encode(address))
def restResponse = restUrl.text
解析RESTful响应

使用 XmlSlurper 可以避免处理命名空间,提取相关字段。示例代码如下:

//Response:
<rdf:RDF
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
    <geo:Point rdf:nodeID="aid76408515">
        <dc:description>
            1600 Pennsylvania Ave NW, Washington DC 20502
        </dc:description>
        <geo:long>-77.037684</geo:long>
        <geo:lat>38.898748</geo:lat>
    </geo:Point>
</rdf:RDF>
def restResponse = restUrl.text
def RDF = new XmlSlurper().parseText(restResponse)
println RDF.Point.description
println RDF.Point.long
println RDF.Point.lat
5. 地理编码服务案例研究:Geocoder.us

许多主流地图网站都提供地理编码API,而Geocoder.us是一个独立的地理编码网站,在多个示例中发挥了重要作用。它允许以多种不同的Web服务方言进行相同的基本查询,并且对于非商业用途是免费的,基于美国人口普查局的免费数据。目前,Geocoder.us不支持RSS和Atom格式,但未来可能会添加这些格式。

以下是不同请求方式的对比表格:
| 请求方式 | 用途 | 示例代码 |
| ---- | ---- | ---- |
| POST | 向服务器提交数据,如表单数据 | 上述POST请求代码 |
| PUT | 更新服务器上的资源 | 上述PUT请求代码 |
| DELETE | 删除服务器上的资源 | 上述DELETE请求代码 |
| RESTful | 获取资源信息,如地理编码 | 上述RESTful请求代码 |

下面是一个简单的mermaid流程图,展示HTTP请求的基本流程:

graph TD;
    A[创建URL对象] --> B[打开连接];
    B --> C{设置请求方法};
    C -- POST --> D[设置doOutput为true并写入数据];
    C -- PUT --> D;
    C -- DELETE --> E[连接服务器];
    C -- GET --> E;
    D --> E;
    E --> F[获取响应内容];

深入理解HTTP请求:POST、PUT、DELETE及各类Web服务请求

6. CSV请求

可以通过发送CSV请求获取地址的经纬度信息。以下是具体的操作步骤:
1. 构建请求URL,将地址进行URL编码后附加到请求URL后面。
2. 打开URL连接并获取响应内容。

示例代码如下:

def partialCsvRequest = "http://geocoder.us/service/csv/geocode?address="
def address = "1600 Pennsylvania Ave, Washington DC"
def csvUrl = new URL(partialCsvRequest + URLEncoder.encode(address))
def csvResponse = csvUrl.text
解析CSV响应

解析CSV响应可以使用 split(",") 方法将响应字符串按逗号分割成数组,然后提取所需的字段。示例代码如下:

//Response:
38.898748,-77.037684,1600 Pennsylvania Ave NW,Washington,DC,20502
def csvResponse = csvUrl.text
def tokens = csvResponse.split(",")
println "Latitude: [${tokens[0]}]"
println "Longitude: [${tokens[1]}]"
println "Address: [${tokens[2]}]"
println "City: [${tokens[3]}]"
println "State: [${tokens[4]}]"
println "Zip: [${tokens[5]}]"
7. SOAP请求

发送SOAP请求获取地址的经纬度信息,需要以下操作步骤:
1. 构建SOAP请求消息,包含请求的地址信息。
2. 打开URL连接,设置请求方法为POST,设置 Content-Type 为 application/xml 。
3. 将SOAP请求消息写入输出流,连接服务器并获取响应内容。

示例代码如下:

def address = "1600 Pennsylvania Av, Washington, DC"
def soapRequest = """<SOAP-ENV:Envelope
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/1999/XMLSchema"
    xmlns:tns="http://rpc.geocoder.us/Geo/Coder/US/">
    <SOAP-ENV:Body>
        <tns:geocode
            SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
            <location xsi:type="xsd:string">${address}</location>
        </tns:geocode>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>"""
def soapUrl = new URL("http://geocoder.us/service/soap")
def connection = soapUrl.openConnection()
connection.setRequestMethod("POST")
connection.setRequestProperty("Content-Type","application/xml")
connection.doOutput = true
Writer writer = new OutputStreamWriter(connection.outputStream)
writer.write(soapRequest)
writer.flush()
writer.close()
connection.connect()
def soapResponse = connection.content.text
解析SOAP响应

使用 XmlSlurper 解析SOAP响应,提取经纬度信息。由于Geocoder.us的SOAP接口存在一些不稳定因素,如命名空间和元素名可能会变化,需要使用更灵活的方式来处理。示例代码如下:

//Response:
<?xml version="1.0" encoding="utf-8"?>
<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
    xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:xsd="http://www.w3.org/1999/XMLSchema"
    SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
    <SOAP-ENV:Body>
        <namesp9:geocodeResponse
            xmlns:namesp9="http://rpc.geocoder.us/Geo/Coder/US/">
            <geo:s-gensym111 xsi:type="SOAP-ENC:Array"
                xmlns:geo="http://rpc.geocoder.us/Geo/Coder/US/"
                SOAP-ENC:arrayType="geo:GeocoderAddressResult[1]">
                <item xsi:type="geo:GeocoderAddressResult">
                    <number xsi:type="xsd:int">1600</number>
                    <lat xsi:type="xsd:float">38.898748</lat>
                    <street xsi:type="xsd:string">Pennsylvania</street>
                    <state xsi:type="xsd:string">DC</state>
                    <city xsi:type="xsd:string">Washington</city>
                    <zip xsi:type="xsd:int">20502</zip>
                    <suffix xsi:type="xsd:string">NW</suffix>
                    <long xsi:type="xsd:float">-77.037684</long>
                    <type xsi:type="xsd:string">Ave</type>
                    <prefix xsi:type="xsd:string" />
                </item>
            </geo:s-gensym111>
        </namesp9:geocodeResponse>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
def soapResponse = connection.content.text
def Envelope = new XmlSlurper().parseText(soapResponse)
println Envelope.Body.geocodeResponse.'s-gensym111'.item.long
println Envelope.Body.geocodeResponse.'s-gensym111'.item.lat
//since the array's name ('s-gensym111') changes with each request
// we can deal with it generically as such:
def itor = Envelope.Body.geocodeResponse.breadthFirst()
while(itor.hasNext()){
    def fragment = itor.next()
    if(fragment.name() == "item"){
        println fragment.lat
        println fragment.long
    }
}
8. XML-RPC请求

发送XML-RPC请求获取地址的经纬度信息,具体操作步骤如下:
1. 构建XML-RPC请求消息,包含请求的方法名和参数。
2. 打开URL连接,设置请求方法为POST,设置 Content-Type 为 application/xml 。
3. 将XML-RPC请求消息写入输出流,连接服务器并获取响应内容。

示例代码如下:

def address = "1600 Pennsylvania Av, Washington, DC"
def xmlrpcRequest = """<methodCall>
    <methodName>geocode</methodName>
    <params>
        <param>
            <value><string>${address}</string></value>
        </param>
    </params>
</methodCall>"""
def xmlrpcUrl = new URL("http://geocoder.us/service/xmlrpc")
def connection = xmlrpcUrl.openConnection()
connection.setRequestMethod("POST")
connection.setRequestProperty("Content-Type","application/xml")
connection.doOutput = true
Writer writer = new OutputStreamWriter(connection.outputStream)
writer.write(xmlrpcRequest)
writer.flush()
writer.close()
connection.connect()
def xmlrpcResponse = connection.content.text
解析XML-RPC响应

使用 XmlSlurper 解析XML-RPC响应,提取经纬度信息。示例代码如下:

//Response:
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse><params><param><value><array><data><value><struct>
    <member><name>number</name><value><int>1600</int></value></member>
    <member><name>lat</name><value><double>38.898748</double></value></member>
    <member><name>street</name><value><string>Pennsylvania</string></value></member>
    <member><name>state</name><value><string>DC</string></value></member>
    <member><name>city</name><value><string>Washington</string></value></member>
    <member><name>zip</name><value><int>20502</int></value></member>
    <member><name>suffix</name><value><string>NW</string></value></member>
    <member><name>long</name><value><double>-77.037684</double></value></member>
    <member><name>type</name><value><string>Ave</string></value></member>
    <member><name>prefix</name><value><string/></value></member>
</struct></value></data></array></value></param></params></methodResponse>
def xmlrpcResponse = connection.content.text
def methodResponse = new XmlSlurper().parseText(xmlrpcResponse)
methodResponse.params.param.value.array.data.value.struct.member.each{member ->
    if(member.name == "lat" || member.name == "long"){
        println "${member.name}: ${member.value.double}"
    }
}

以下是不同请求类型在数据格式和处理方式上的对比表格:
| 请求类型 | 数据格式 | 数据处理方式 |
| ---- | ---- | ---- |
| CSV请求 | 逗号分隔值 | 使用 split(",") 方法解析 |
| SOAP请求 | XML | 使用 XmlSlurper 解析,需处理不稳定的命名空间和元素名 |
| XML-RPC请求 | XML | 使用 XmlSlurper 解析 |

下面是一个mermaid流程图,展示不同类型请求的处理流程:

graph TD;
    A[选择请求类型] --> B{CSV请求};
    B -- 是 --> C[构建CSV请求URL并获取响应];
    B -- 否 --> D{SOAP请求};
    D -- 是 --> E[构建SOAP请求消息并发送];
    D -- 否 --> F{XML-RPC请求};
    F -- 是 --> G[构建XML-RPC请求消息并发送];
    F -- 否 --> H[其他请求类型];
    C --> I[解析CSV响应];
    E --> J[解析SOAP响应];
    G --> K[解析XML-RPC响应];

综上所述,通过不同的HTTP请求方式(POST、PUT、DELETE、RESTful、CSV、SOAP、XML - RPC)可以实现向服务器提交数据、更新资源、删除资源以及获取各种格式的资源信息等功能。在实际应用中,需要根据具体的需求选择合适的请求方式,并正确处理响应内容。

相关推荐

告别 RPA 和 Selenium,MCP + Playwright 成为自动化开发新宠!

摘要: 随着数字化转型加速,传统自动化工具(如RPA和Selenium)在复杂场景中暴露出开发成本高、灵活性不足等问题。新一代解决方案MCP(Model Context Protocol)与Playwright的结合,通过AI与自动化的无缝对接,实现了智能化的任务处理。MCP支持自然语言交互和上下文感知,开发者无需编写复杂代码即可生成自动化脚本;Playwright则提供多浏览器支持、高性能和易用性。二者结合显著提升开发效率,使自动化更智能、灵活。文章还对比了VS Code与Trae中配置Playwrigh

我先测了 2208

BERTopic安装指南:hdbscan依赖问题全解析(附解决方案)

本文详细解析了安装BERTopic时常见的hdbscan依赖报错问题,深入剖析了C++编译环境缺失、Python版本兼容性以及包管理渠道混用三大核心原因。针对Windows、macOS和Linux不同系统,提供了创建虚拟环境、使用conda安装预编译包、安装C++编译工具等具体解决方案,帮助用户顺利安装BERTopic并开始文本主题建模实践。

weixin_29061041的博客 212

提取abaqus中节点集合的应力应变

节点是没有应力应变的,只有积分点才有,所以直接在odb文件里面用FieldOutput是整不出来的(结果是个空列表),只能用session这种让abaqus自己帮你处理。具体的代码需要根据自己操作的时候abaqus.rpy这个文件中代码的变化来更改。

蓝胖子的博客 4553

LangGraph的容错机制:从节点失败到图级回滚

核心概念铺垫:讲解LLM应用容错与事务性的核心概念(幂等性、重试策略、降级策略、快照、回滚、原子性、一致性、隔离性、持久性、最终一致性),对比LangGraph容错机制与传统数据库ACID事务、Apache Airflow/Kubernetes Workflow/Kubeflow Pipelines容错机制的异同;LangGraph容错机制的演进历史:用markdown表格梳理LangGraph从0.0.1到1.5.0(截止202X年X月)的容错机制发展历程;节点级别的容错:重试与降级。

AI Python 编程之道的博客 172

机器学习模型——非线性回归

升维是一种常用的处理非线性问题的方法,它通过将原始数据从低维空间映射到高维空间来增强模型的表达能力。我们可以看出,二维数据用一维直线很难去很好的拟合。升维里的degree设置的不易过大,否则容易造成维度灾难。升维后,拟合的线与原数据比较符合。将非线性问题转换为线性问题。

qq_60688380的博客 1421

I2C通信——时序图

本文用逻辑分析仪抓取主机I2C通信的时序图,抓取的过程是读某个寄存器的值。

weixin_43772611的博客 7353

RK3588 buildroot 双网口bonding调试

本文介绍了Rockchip Buildroot中配置网络冗余的方法,通过bonding技术将多个物理网口合并为逻辑接口。主要内容包括:1)7种常见bonding模式的特点及适用场景;2)RK3588的具体配置流程,包括内核配置(启用bonding驱动、修改dts)、添加ifenslave工具;3)系统编译和网络状态检查。

501846585_QQAndroid_java 458

Transformer实战(32)——Transformer模型压缩

在本节中,我们学习了如何在硬件资源受限的情况下减轻运行大模型的负担。我们介绍了如何通过蒸馏、剪枝和量化从训练好的模型中提取高效模型。预训练轻量级的通用语言模型(如 DistilBERT) 可以在各种任务上进行微调,并表现出与非蒸馏模型相当的性能。随着数据量的不断增加,我们希望模型能够更快地运行,在这方面,高效 Transformer 起着至关重要的作用。

盼小辉丶的博客 2547

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

上一篇: 52、俄罗斯卡片问题与图类识别的分布式交互证明
下一篇: 6、智能交通与辅助出行技术创新:自动跟踪太阳的智能轮椅与区块链安全框架
http9protocoller
博客等级 码龄1天 0粉丝 1782原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值